From 926c825d0c7f0a373fb6bd22d88d0df850407f3c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 7 Jul 2015 15:37:42 +0300 Subject: [PATCH 001/675] 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 002/675] 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 003/675] 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 004/675] 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 005/675] 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 006/675] 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 007/675] 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 008/675] 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 009/675] 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 010/675] 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 011/675] 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 012/675] 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 013/675] 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 014/675] 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 015/675] 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 016/675] 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 017/675] 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 e0983c815c32c9b79d340100ab2b4b6750820554 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sat, 11 Jul 2015 22:17:53 +0300 Subject: [PATCH 018/675] 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 019/675] 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 c266315a355480ad6e4bc665e5d4150c6c8de8f3 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 12 Jul 2015 15:20:22 +0300 Subject: [PATCH 020/675] 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 021/675] 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 022/675] 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 c8c79dc1efa5682c52ead7221628812638a55fed Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 13 Jul 2015 10:53:31 +0300 Subject: [PATCH 023/675] 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 024/675] 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 22:37:14 +0300 Subject: [PATCH 025/675] 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 5e623a2a1d06d5679f214cad95123a1d3bd88b34 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 14 Jul 2015 16:18:33 +0300 Subject: [PATCH 026/675] 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 027/675] 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 e8a9567be30fb35e78e252bf52e95bcebe76a109 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 15 Jul 2015 19:39:01 +0300 Subject: [PATCH 028/675] 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 3ba73f5fd9feb9727b56f32767c848e520d9a94c Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Wed, 15 Jul 2015 20:53:08 +0300 Subject: [PATCH 029/675] 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 ad353e6dd0b41e388e2ec3fbcc4bf15d1ef71e57 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 16 Jul 2015 19:52:31 +0300 Subject: [PATCH 030/675] 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 031/675] 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 032/675] 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 033/675] 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 034/675] 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 035/675] 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 036/675] 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 037/675] 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 f5745749a6e7875c487ac417dead00446af805c2 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 19 Jul 2015 22:50:42 +0300 Subject: [PATCH 038/675] 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 039/675] 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 4a16eba716d6795bb9aadc492c4417d1a05828ef Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Mon, 20 Jul 2015 17:23:14 +0300 Subject: [PATCH 040/675] 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 041/675] 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 042/675] 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 043/675] 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 044/675] 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 045/675] 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 9a8ca819073e54406daafd04319299429c089c4e Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Sun, 26 Jul 2015 13:54:36 +0300 Subject: [PATCH 046/675] 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 f9b0b7ede5eb2bc8ef62fce47c495247b04ebd78 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Tue, 28 Jul 2015 15:04:22 +0300 Subject: [PATCH 047/675] 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 f15adb4e4f18e9f5509c95a065001f85a4e0dd82 Mon Sep 17 00:00:00 2001 From: Stanislav Bas Date: Thu, 30 Jul 2015 14:43:36 +0300 Subject: [PATCH 048/675] 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 049/675] 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 9f0e059a15106eb5fa8f1174eadd91076623e7d3 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 28 Oct 2015 11:18:48 +1100 Subject: [PATCH 050/675] 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 051/675] 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 052/675] 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 053/675] 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 054/675] 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 055/675] 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 e13eb625d38a13b47d1b6680608c69c20de6842a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 26 Oct 2015 21:36:19 +0100 Subject: [PATCH 056/675] 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 057/675] 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 058/675] 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 059/675] 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 060/675] 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 061/675] 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 062/675] 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 063/675] 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 064/675] 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 065/675] 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 066/675] 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 067/675] 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 068/675] 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 069/675] 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 070/675] 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 071/675] 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 072/675] 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 073/675] 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 074/675] 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 075/675] 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 076/675] 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 077/675] 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 078/675] 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 079/675] 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 080/675] 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 081/675] 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 082/675] 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 083/675] 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 084/675] 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 085/675] 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 086/675] 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 087/675] 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 088/675] 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 089/675] 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 090/675] 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 091/675] 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 092/675] 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 093/675] 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 094/675] 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 095/675] 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 096/675] 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 097/675] 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 098/675] 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 099/675] 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 100/675] 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 101/675] 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 102/675] 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 103/675] 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 104/675] 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 105/675] 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 106/675] 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 107/675] 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 108/675] 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 109/675] 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 110/675] 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 111/675] 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 112/675] 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 113/675] 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 114/675] 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 115/675] 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 116/675] 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 117/675] 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 118/675] 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 119/675] 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 120/675] 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 121/675] 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 122/675] 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 123/675] 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 124/675] 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 125/675] 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 126/675] 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 127/675] 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 128/675] 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 129/675] 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 130/675] 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 131/675] 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 132/675] 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 133/675] 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 134/675] 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 135/675] 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 136/675] 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 137/675] 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 138/675] 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 139/675] 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 140/675] 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 141/675] 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 142/675] 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 143/675] 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 144/675] 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 145/675] 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 146/675] 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 147/675] 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 148/675] 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 149/675] 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 150/675] 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 151/675] 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 152/675] 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 153/675] 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 154/675] 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 155/675] 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 156/675] 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 157/675] 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 158/675] 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 159/675] 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 160/675] 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 161/675] 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 162/675] 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 163/675] 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 164/675] 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 165/675] 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 166/675] 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 167/675] 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 168/675] 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 169/675] 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 170/675] 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 171/675] 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 172/675] 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 173/675] 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 174/675] 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 175/675] 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 176/675] 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 177/675] 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 178/675] 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 179/675] 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 180/675] 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 181/675] 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 182/675] 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 183/675] 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 184/675] 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 185/675] 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 186/675] 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 187/675] 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 188/675] 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 189/675] 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 190/675] 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 191/675] 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 192/675] 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 193/675] 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 194/675] 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 195/675] 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 196/675] 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 197/675] 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 198/675] 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 199/675] 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 200/675] 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 201/675] 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 202/675] 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 203/675] 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 204/675] 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 205/675] 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 206/675] 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 207/675] 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 208/675] 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 209/675] 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 210/675] 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 211/675] 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 212/675] 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 213/675] 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 214/675] 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 215/675] 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 216/675] 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 217/675] 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 218/675] 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 219/675] 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 220/675] 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 221/675] 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 222/675] 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 223/675] 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 224/675] 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 225/675] 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 226/675] 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 227/675] 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 228/675] 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 229/675] 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 230/675] 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 231/675] 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 232/675] 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 233/675] 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 234/675] 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 235/675] 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 236/675] 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 237/675] 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 238/675] 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 239/675] 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 240/675] 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 241/675] 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 242/675] 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 243/675] 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 244/675] 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 245/675] 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 246/675] 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 247/675] 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 248/675] 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 249/675] 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 250/675] 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 251/675] 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 252/675] 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 253/675] 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 254/675] 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 255/675] 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 256/675] 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 257/675] 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 258/675] 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 259/675] 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 260/675] 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 261/675] 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 262/675] 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 263/675] 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 264/675] 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 265/675] 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 266/675] 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 267/675] 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 268/675] 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 269/675] 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 270/675] 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 271/675] 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 272/675] 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 273/675] 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 274/675] 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 275/675] 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 276/675] 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 277/675] 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 278/675] 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 279/675] 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 280/675] 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 281/675] 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 282/675] 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 283/675] 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 284/675] 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 285/675] 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 286/675] 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 287/675] 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 288/675] 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 289/675] 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 290/675] 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 291/675] 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 292/675] 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 293/675] 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 294/675] 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 295/675] 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 296/675] 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 297/675] 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 298/675] 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 299/675] 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 300/675] 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 301/675] 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 302/675] 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 303/675] 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 304/675] 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 305/675] 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 306/675] 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 307/675] 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 308/675] 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 309/675] 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 310/675] 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 311/675] 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 312/675] 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 313/675] 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 314/675] 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 315/675] 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 316/675] 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 317/675] 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 318/675] 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 319/675] 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 320/675] 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 321/675] 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 322/675] 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 323/675] 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 324/675] 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 325/675] 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 326/675] 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 327/675] 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 328/675] 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 329/675] 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 330/675] 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 331/675] 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 332/675] 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 333/675] 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 334/675] 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 335/675] 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 336/675] 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 337/675] 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 338/675] 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 339/675] 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 340/675] 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 341/675] 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 342/675] 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 343/675] 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 344/675] 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 345/675] 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 346/675] 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 347/675] 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 348/675] 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 349/675] 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 350/675] 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 351/675] 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 352/675] 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 353/675] 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 354/675] 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 355/675] 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 356/675] 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 357/675] 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 358/675] 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 359/675] 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 360/675] 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 361/675] 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 362/675] 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 363/675] 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 364/675] 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 365/675] 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 366/675] 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 367/675] 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 368/675] 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 369/675] 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 370/675] 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 371/675] 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 372/675] 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 373/675] 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 374/675] 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 375/675] 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 376/675] 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 377/675] 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 378/675] 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 379/675] 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 380/675] 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 381/675] 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 382/675] 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 383/675] 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 384/675] 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 385/675] 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 386/675] 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 387/675] 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 388/675] 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 389/675] 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 390/675] 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 391/675] 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 392/675] 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 393/675] 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 394/675] 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 395/675] 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 396/675] 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 397/675] 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 398/675] 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 399/675] 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 400/675] 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 401/675] 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 402/675] 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 403/675] 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 404/675] 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 405/675] 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 406/675] 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 407/675] 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 408/675] 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 409/675] 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 410/675] 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 411/675] 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 412/675] 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 413/675] 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 414/675] 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 415/675] 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 416/675] 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 417/675] 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 418/675] 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 419/675] 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 420/675] 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 421/675] 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 422/675] 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 423/675] 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 424/675] 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 425/675] 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 426/675] 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 427/675] 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 428/675] 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 429/675] 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 430/675] 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 431/675] 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 432/675] 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 433/675] 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 434/675] 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 435/675] 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 436/675] 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 437/675] 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 438/675] 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 439/675] 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 440/675] 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 441/675] 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 442/675] 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 443/675] 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 444/675] 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 445/675] 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 446/675] 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 447/675] 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 448/675] 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 449/675] 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 450/675] 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 451/675] 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 452/675] 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 453/675] 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 454/675] 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 455/675] 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 456/675] 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 457/675] 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 458/675] 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 459/675] 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 460/675] 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 461/675] 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 462/675] 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 463/675] 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 464/675] 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 465/675] 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 466/675] 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 467/675] 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 468/675] 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 469/675] 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 470/675] 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 471/675] 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 472/675] 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 473/675] 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 474/675] 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 475/675] 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 476/675] 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 477/675] 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 478/675] 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 479/675] 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 480/675] 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 481/675] 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 482/675] 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 483/675] 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 484/675] 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 485/675] 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 486/675] 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 487/675] 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 488/675] 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 489/675] 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 490/675] 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 491/675] 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 492/675] 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 493/675] 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 494/675] 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 495/675] 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 496/675] 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 497/675] 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 498/675] 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 499/675] 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 500/675] 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 501/675] 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 502/675] 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 503/675] 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 504/675] 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 505/675] 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 506/675] 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 507/675] 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 508/675] 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 509/675] 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 510/675] 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 511/675] 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 512/675] 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 513/675] 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 514/675] 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 515/675] 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 516/675] 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 517/675] 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 518/675] 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 519/675] 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 520/675] 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 521/675] 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 522/675] 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 523/675] 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 524/675] 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 525/675] 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 526/675] 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 527/675] 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 528/675] 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 529/675] 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 530/675] 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 531/675] 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 532/675] 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 533/675] 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 534/675] 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 535/675] 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 536/675] 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 537/675] 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 538/675] 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 539/675] 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 540/675] 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 541/675] 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 542/675] 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 543/675] 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 544/675] 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 545/675] 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 546/675] 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 547/675] 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 548/675] 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 549/675] 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 550/675] 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 551/675] 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 552/675] 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 553/675] 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 554/675] 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 555/675] 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 556/675] 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 557/675] 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 558/675] 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 559/675] 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 560/675] 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 561/675] 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 562/675] 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 563/675] 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 564/675] 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 565/675] 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 566/675] 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 567/675] 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 568/675] 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 569/675] 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 570/675] 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 571/675] 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 572/675] 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 573/675] 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 574/675] 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 575/675] 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 576/675] 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 577/675] 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 578/675] 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 579/675] 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 580/675] 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 581/675] 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 582/675] 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 583/675] 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 584/675] 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 585/675] 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 586/675] 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 587/675] 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 588/675] 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 589/675] 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 590/675] 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 591/675] 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 592/675] 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 593/675] 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 594/675] 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 595/675] 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 596/675] 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 597/675] 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 598/675] 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 599/675] 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 600/675] 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 601/675] 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 602/675] 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 603/675] 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 604/675] 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 605/675] 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 606/675] 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 607/675] 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 608/675] 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 609/675] 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 610/675] 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 611/675] 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 612/675] 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 613/675] 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 614/675] 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 615/675] 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 616/675] 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 617/675] 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 618/675] 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 619/675] 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 620/675] 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 621/675] 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 622/675] 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 623/675] 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 624/675] 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 625/675] 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 626/675] 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 627/675] 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 628/675] 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 629/675] 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 630/675] 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 631/675] 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 632/675] 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 633/675] 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 634/675] 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 635/675] 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 636/675] 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 637/675] 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 638/675] 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 639/675] 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 640/675] 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 641/675] 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 642/675] 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 643/675] 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 644/675] 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 645/675] 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 646/675] 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 647/675] 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 648/675] 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 649/675] 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 650/675] 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 651/675] 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 652/675] 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 653/675] 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 654/675] 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 655/675] 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 656/675] 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 657/675] 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 658/675] 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 659/675] 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 660/675] 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 661/675] 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 662/675] 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 663/675] 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 664/675] 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 665/675] 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 666/675] 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 667/675] 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 668/675] 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 669/675] 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 670/675] 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 671/675] 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 672/675] 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 673/675] 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 674/675] 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 675/675] 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)