From 6f22d819c51fbd9499952507caaa34bac6c4686d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 31 Aug 2017 12:36:54 +0400 Subject: [PATCH 01/44] Do not allow to switch weapon to probe or lockpick during attack --- apps/openmw/mwclass/lockpick.cpp | 11 +++++++++++ apps/openmw/mwclass/lockpick.hpp | 2 ++ apps/openmw/mwclass/probe.cpp | 11 +++++++++++ apps/openmw/mwclass/probe.hpp | 2 ++ apps/openmw/mwgui/quickkeysmenu.cpp | 5 +++-- 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index b8f6f5ecb..15499c1a8 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -3,6 +3,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -155,6 +156,16 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } + std::pair Lockpick::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const + { + // Do not allow equip tools from inventory during attack + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc) + && MWBase::Environment::get().getWindowManager()->isGuiMode()) + return std::make_pair(0, "#{sCantEquipWeapWarning}"); + + return std::make_pair(1, ""); + } + 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 efa675c95..1bcf7fb85 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -51,6 +51,8 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; + virtual std::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index ecaa056f9..030ee3f8b 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -3,6 +3,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -155,6 +156,16 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } + std::pair Probe::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const + { + // Do not allow equip tools from inventory during attack + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc) + && MWBase::Environment::get().getWindowManager()->isGuiMode()) + return std::make_pair(0, "#{sCantEquipWeapWarning}"); + + return std::make_pair(1, ""); + } + 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 f67d8af86..9ac3ab0c9 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -51,6 +51,8 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; + virtual std::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 4e4462409..e912193bf 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -344,16 +344,17 @@ namespace MWGui { MWWorld::Ptr item = *button->getUserData(); bool isWeapon = item.getTypeName() == typeid(ESM::Weapon).name(); + bool isTool = item.getTypeName() == typeid(ESM::Probe).name() || item.getTypeName() == typeid(ESM::Lockpick).name(); // delay weapon switching if player is busy - if (isDelayNeeded && isWeapon) + if (isDelayNeeded && (isWeapon || isTool)) { mActivatedIndex = index; return; } // disable weapon switching if player is dead or paralyzed - if (isReturnNeeded && isWeapon) + if (isReturnNeeded && (isWeapon || isTool)) { return; } From 91dcd5bc6e6de5ee25231c9b64e75206dba3ddb7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 31 Aug 2017 13:28:09 +0400 Subject: [PATCH 02/44] Do not allow to unequip weapon from inventory during attack --- apps/openmw/mwgui/inventorywindow.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4cba7a0ae..6a2d3ff83 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -255,6 +255,19 @@ namespace MWGui } } + // If we unequip weapon during attack, it can lead to unexpected behaviour + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPtr)) + { + bool isWeapon = item.mBase.getTypeName() == typeid(ESM::Weapon).name(); + MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); + + if (isWeapon && invStore.isEquipped(item.mBase)) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sCantEquipWeapWarning}"); + return; + } + } + if (count > 1 && !shift) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); From b9931fb71cb028aa8f8bb9eefb611ecb23ec096e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 31 Aug 2017 21:39:21 +0000 Subject: [PATCH 03/44] Set the shader on the node containing the StateSet --- components/shader/shadervisitor.cpp | 21 +++++++++++---------- components/shader/shadervisitor.hpp | 7 +++++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index d85b72203..2d5fdfb39 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -26,6 +26,7 @@ namespace Shader , mMaterialOverridden(false) , mNormalHeight(false) , mTexStageRequiringTangents(-1) + , mNode(NULL) { } @@ -69,7 +70,7 @@ namespace Shader { if (node.getStateSet()) { - pushRequirements(); + pushRequirements(node); applyStateSet(node.getStateSet(), node); traverse(node); popRequirements(); @@ -234,9 +235,10 @@ namespace Shader } } - void ShaderVisitor::pushRequirements() + void ShaderVisitor::pushRequirements(osg::Node& node) { mRequirements.push_back(mRequirements.back()); + mRequirements.back().mNode = &node; } void ShaderVisitor::popRequirements() @@ -244,8 +246,9 @@ namespace Shader mRequirements.pop_back(); } - void ShaderVisitor::createProgram(const ShaderRequirements &reqs, osg::Node& node) + void ShaderVisitor::createProgram(const ShaderRequirements &reqs) { + osg::Node& node = *reqs.mNode; osg::StateSet* writableStateSet = NULL; if (mAllowedToModifyStateSets) writableStateSet = node.getOrCreateStateSet(); @@ -305,9 +308,9 @@ namespace Shader void ShaderVisitor::apply(osg::Geometry& geometry) { bool needPop = (geometry.getStateSet() != NULL); - if (geometry.getStateSet()) + if (geometry.getStateSet()) // TODO: check if stateset affects shader permutation before pushing it { - pushRequirements(); + pushRequirements(geometry); applyStateSet(geometry.getStateSet(), geometry); } @@ -350,9 +353,8 @@ namespace Shader rig->setSourceGeometry(sourceGeometry); } - // TODO: find a better place for the stateset if (useShader) - createProgram(reqs, geometry); + createProgram(reqs); } if (needPop) @@ -366,16 +368,15 @@ namespace Shader if (drawable.getStateSet()) { - pushRequirements(); + pushRequirements(drawable); applyStateSet(drawable.getStateSet(), drawable); } if (!mRequirements.empty()) { const ShaderRequirements& reqs = mRequirements.back(); - // TODO: find a better place for the stateset if (reqs.mShaderRequired || mForceShaders) - createProgram(reqs, drawable); + createProgram(reqs); } if (needPop) diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index 8f4597ff3..83f28e063 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -52,7 +52,7 @@ namespace Shader void applyStateSet(osg::ref_ptr stateset, osg::Node& node); - void pushRequirements(); + void pushRequirements(osg::Node& node); void popRequirements(); private: @@ -89,13 +89,16 @@ namespace Shader // -1 == no tangents required int mTexStageRequiringTangents; + + // the Node that requested these requirements + osg::Node* mNode; }; std::vector mRequirements; std::string mDefaultVsTemplate; std::string mDefaultFsTemplate; - void createProgram(const ShaderRequirements& reqs, osg::Node& node); + void createProgram(const ShaderRequirements& reqs); }; } From 45f7563a5579bcf3674cc44c5d9d3bd80b1c0e80 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 31 Aug 2017 21:40:35 +0000 Subject: [PATCH 04/44] Revert "Revert "Check for a Geometry node when attaching bodyparts"" Issue with shaders has been fixed with b9931fb71cb028aa8f8bb9eefb611ecb23ec096e This reverts commit a1e3fb7604a11307ed08f1ec84b31a359cb5ead5. --- components/nifosg/nifloader.cpp | 3 +++ components/sceneutil/attach.cpp | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 78186c439..b7d1c15b8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1130,6 +1130,8 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); } + geometry->setName(triShape->name); + if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch @@ -1219,6 +1221,7 @@ namespace NifOsg osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); + rig->setName(triShape->name); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 1385f771e..8634a4df6 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -32,29 +32,29 @@ namespace SceneUtil virtual void apply(osg::MatrixTransform& node) { - applyNode(node); - } - virtual void apply(osg::Geometry& node) - { - applyNode(node); + traverse(node); } virtual void apply(osg::Node& node) { - applyNode(node); + traverse(node); } virtual void apply(osg::Group& node) { - applyNode(node); + traverse(node); } - void applyNode(osg::Node& node) + virtual void apply(osg::Geometry& geom) { - std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); + std::string lowerName = Misc::StringUtils::lowerCase(geom.getName()); if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) - mToCopy.push_back(&node); - else - traverse(node); + { + osg::Node* node = &geom; + while (node && node->getNumParents() && !node->getStateSet()) + node = node->getParent(0); + if (node) + mToCopy.push_back(node); + } } void doCopy() From a8005c33d9ea82ffa49c30f40022908f7215261e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 31 Aug 2017 21:57:26 +0000 Subject: [PATCH 05/44] Revert unintended change to mOnGround variable that was somehow introduced with 38a2de3c51edd808e5a3acba9e94c8ed11d227dd --- apps/openmw/mwphysics/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index e5e36def8..79c6dcabf 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -18,7 +18,7 @@ namespace MWPhysics Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) : mCanWaterWalk(false), mWalkingOnWater(false) - , mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(false), mOnSlope(false) + , mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) , mInternalCollisionMode(true) , mExternalCollisionMode(true) , mCollisionWorld(world) From 0d7279ea2a6086232bc8235597924579f1aecd3f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Sep 2017 08:59:05 +0400 Subject: [PATCH 06/44] Fixes a regression with bound weapons equipping (bug #4050) --- apps/openmw/mwclass/weapon.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 62a9b6d0f..9fb4a9767 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -374,7 +374,9 @@ namespace MWClass if (hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); - if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc)) + // Do not allow equip weapons from inventory during attack + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc) + && MWBase::Environment::get().getWindowManager()->isGuiMode()) return std::make_pair(0, "#{sCantEquipWeapWarning}"); std::pair, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); From a5b01fefec97ca69e07872034853f2bd7f24b9c4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Sep 2017 09:34:15 +0400 Subject: [PATCH 07/44] Allow to interrupt an attack, if attack button is held --- apps/openmw/mwbase/mechanicsmanager.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 6 +++++- apps/openmw/mwmechanics/actors.cpp | 10 ++++++++++ apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 6 ++++++ apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 +++++ apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 ++ 8 files changed, 31 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7e1059d06..84d43156e 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -247,6 +247,7 @@ namespace MWBase virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0; + virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr) = 0; virtual bool isRunning(const MWWorld::Ptr& ptr) = 0; virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; }; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 5f3e3152d..e4fa8fc2b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -948,7 +948,11 @@ namespace MWInput if (!mControlSwitch["playerfighting"] || !mControlSwitch["playercontrols"]) return; - if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer())) + // We want to interrupt animation only if attack is prepairing, but still is not triggered + // Otherwise we will get a "speedshooting" exploit, when player can skip reload animation by hitting "Toggle Weapon" key twice + if (MWBase::Environment::get().getMechanicsManager()->isAttackPrepairing(mPlayer->getPlayer())) + mPlayer->setAttackingOrSpell(false); + else if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer())) return; MWMechanics::DrawState_ state = mPlayer->getDrawState(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index fba8d1a4d..ed510e616 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -802,6 +802,16 @@ namespace MWMechanics } } + bool Actors::isAttackPrepairing(const MWWorld::Ptr& ptr) + { + PtrActorMap::iterator it = mActors.find(ptr); + if (it == mActors.end()) + return false; + CharacterController* ctrl = it->second->getCharacterController(); + + return ctrl->isAttackPrepairing(); + } + bool Actors::isRunning(const MWWorld::Ptr& ptr) { PtrActorMap::iterator it = mActors.find(ptr); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 052bf4920..6eb3a2955 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -107,6 +107,7 @@ namespace MWMechanics int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + bool isAttackPrepairing(const MWWorld::Ptr& ptr); bool isRunning(const MWWorld::Ptr& ptr); bool isSneaking(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index e9f42476b..51dc37e18 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2218,6 +2218,12 @@ void CharacterController::setAttackTypeBasedOnMovement() mAttackType = "chop"; } +bool CharacterController::isAttackPrepairing() const +{ + return mUpperBodyState == UpperCharState_StartToMinAttack || + mUpperBodyState == UpperCharState_MinAttackToMaxAttack; +} + bool CharacterController::isReadyToBlock() const { return updateCarriedLeftVisible(mWeaponType); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index bde64cdfb..9bcad0994 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -263,6 +263,7 @@ public: void forceStateUpdate(); + bool isAttackPrepairing() const; bool isReadyToBlock() const; bool isKnockedOut() const; bool isSneaking() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 83780e9f8..5f3dd58af 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -423,6 +423,11 @@ namespace MWMechanics mObjects.update(duration, paused); } + bool MechanicsManager::isAttackPrepairing(const MWWorld::Ptr& ptr) + { + return mActors.isAttackPrepairing(ptr); + } + bool MechanicsManager::isRunning(const MWWorld::Ptr& ptr) { return mActors.isRunning(ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 47dc6e6a2..adad21916 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -210,8 +210,10 @@ namespace MWMechanics virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count); + virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr); virtual bool isRunning(const MWWorld::Ptr& ptr); virtual bool isSneaking(const MWWorld::Ptr& ptr); + private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); From 7f5f5458d448fbc8eaa422047d14d6c0762b6733 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Sep 2017 18:03:23 +0400 Subject: [PATCH 08/44] Reset player attack animation when unequip weapon or tool --- apps/openmw/mwrender/npcanimation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 73927e0ab..e4d0abf7b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -23,6 +23,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" @@ -919,6 +920,9 @@ void NpcAnimation::showWeapons(bool showWeapon) else { removeIndividualPart(ESM::PRT_Weapon); + // If we remove/hide weapon from player, we should reset attack animation as well + if (mPtr == MWMechanics::getPlayer()) + MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); } } From 132ac6001b36c91f59465204f8e799c32346ae89 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 18:24:48 +0200 Subject: [PATCH 09/44] Fix bug of Animation::mSkeleton not being assigned This bug resulted in deactivating a Skeleton not working properly for creatures (that are out of processing range), therefore reduced performance. --- apps/openmw/mwrender/animation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 98d29bfc9..22bafaa71 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1192,6 +1192,9 @@ namespace MWRender mObjectRoot->addChild(created); mInsert->addChild(mObjectRoot); } + osg::ref_ptr skel = dynamic_cast(mObjectRoot.get()); + if (skel) + mSkeleton = skel.get(); } else { From 209e139aa89015cad87b39dc160f9a5af0998040 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 18:27:00 +0200 Subject: [PATCH 10/44] Move double buffering implementation inside RigGeometry The double buffering is an implementation detail so it should be handled as such, rather than mandating the scene graph to be structured in a certain way. Override accept(NodeVisitor&) instead of using callbacks. --- components/nifosg/nifloader.cpp | 13 +- components/sceneutil/attach.cpp | 6 +- components/sceneutil/riggeometry.cpp | 193 +++++++++++---------------- components/sceneutil/riggeometry.hpp | 20 +-- components/sceneutil/serialize.cpp | 2 +- components/sceneutil/skeleton.cpp | 17 +-- components/sceneutil/skeleton.hpp | 2 - 7 files changed, 97 insertions(+), 156 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b7d1c15b8..6b603cc9e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1236,7 +1236,6 @@ namespace NifOsg SceneUtil::RigGeometry::BoneInfluence influence; const std::vector &weights = data->bones[i].weights; - //influence.mWeights.reserve(weights.size()); for(size_t j = 0;j < weights.size();j++) { std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); @@ -1249,17 +1248,7 @@ namespace NifOsg } rig->setInfluenceMap(map); - // 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; - - SceneUtil::RigGeometry* rig2 = osg::clone(rig.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES); - frameswitch->addChild(rig); - frameswitch->addChild(rig2); - - parentNode->addChild(frameswitch); + parentNode->addChild(rig); } osg::BlendFunc::BlendFuncMode getBlendMode(int mode) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 8634a4df6..1df1be27f 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -43,13 +43,13 @@ namespace SceneUtil traverse(node); } - virtual void apply(osg::Geometry& geom) + virtual void apply(osg::Drawable& drawable) { - std::string lowerName = Misc::StringUtils::lowerCase(geom.getName()); + std::string lowerName = Misc::StringUtils::lowerCase(drawable.getName()); if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) { - osg::Node* node = &geom; + osg::Node* node = &drawable; while (node && node->getNumParents() && !node->getStateSet()) node = node->getParent(0); if (node) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 9adfdcddb..ec01f62d0 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -10,73 +10,17 @@ namespace SceneUtil { -class UpdateRigBounds : public osg::Drawable::UpdateCallback -{ -public: - UpdateRigBounds() - { - } - - UpdateRigBounds(const UpdateRigBounds& copy, const osg::CopyOp& copyop) - : osg::Drawable::UpdateCallback(copy, copyop) - { - } - - META_Object(SceneUtil, UpdateRigBounds) - - void update(osg::NodeVisitor* nv, osg::Drawable* drw) - { - RigGeometry* rig = static_cast(drw); - - rig->updateBounds(nv); - } -}; - -// TODO: make threadsafe for multiple cull threads -class UpdateRigGeometry : public osg::Drawable::CullCallback -{ -public: - UpdateRigGeometry() - { - } - - UpdateRigGeometry(const UpdateRigGeometry& copy, const osg::CopyOp& copyop) - : osg::Drawable::CullCallback(copy, copyop) - { - } - - META_Object(SceneUtil, UpdateRigGeometry) - - virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* drw, osg::State*) const - { - RigGeometry* geom = static_cast(drw); - geom->update(nv); - return false; - } -}; - -// 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) , mBoundsFirstFrame(true) { - setCullCallback(new UpdateRigGeometry); - setUpdateCallback(new UpdateRigBounds); - setSupportsDisplayList(false); - setUseVertexBufferObjects(true); - setComputeBoundingBoxCallback(new DummyComputeBoundCallback); + setUpdateCallback(new osg::Callback); // dummy to make sure getNumChildrenRequiringUpdateTraversal() is correct + // update done in accept(NodeVisitor&) } RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) - : osg::Geometry(copy, copyop) + : Drawable(copy, copyop) , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) , mLastFrameNumber(0) @@ -89,57 +33,47 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) { mSourceGeometry = sourceGeometry; - osg::Geometry& from = *sourceGeometry; - - if (from.getStateSet()) - setStateSet(from.getStateSet()); - - // shallow copy primitive sets & vertex attributes that we will not modify - setPrimitiveSetList(from.getPrimitiveSetList()); - setColorArray(from.getColorArray()); - setSecondaryColorArray(from.getSecondaryColorArray()); - setFogCoordArray(from.getFogCoordArray()); - - // need to copy over texcoord list manually due to a missing null pointer check in setTexCoordArrayList(), this has been fixed in OSG 3.5 - osg::Geometry::ArrayList& texCoordList = from.getTexCoordArrayList(); - for (unsigned int i=0; i vbo (new osg::VertexBufferObject); - vbo->setUsage(GL_DYNAMIC_DRAW_ARB); - - osg::ref_ptr vertexArray = osg::clone(from.getVertexArray(), osg::CopyOp::DEEP_COPY_ALL); - if (vertexArray) - { - vertexArray->setVertexBufferObject(vbo); - setVertexArray(vertexArray); - } - - if (osg::Array* normals = from.getNormalArray()) + for (unsigned int i=0; i<2; ++i) { - osg::ref_ptr normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL); - if (normalArray) + osg::Geometry& from = *sourceGeometry; + mGeometry[i] = new osg::Geometry(from, osg::CopyOp::SHALLOW_COPY); + osg::Geometry& to = *mGeometry[i]; + to.setSupportsDisplayList(false); + to.setUseVertexBufferObjects(true); + to.setCullingActive(false); // make sure to disable culling since that's handled by this class + + // vertices and normals are modified every frame, so we need to deep copy them. + // assign a dedicated VBO to make sure that modifications don't interfere with source geometry's VBO. + osg::ref_ptr vbo (new osg::VertexBufferObject); + vbo->setUsage(GL_DYNAMIC_DRAW_ARB); + + osg::ref_ptr vertexArray = osg::clone(from.getVertexArray(), osg::CopyOp::DEEP_COPY_ALL); + if (vertexArray) { - normalArray->setVertexBufferObject(vbo); - setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); + vertexArray->setVertexBufferObject(vbo); + to.setVertexArray(vertexArray); } - } + if (osg::Array* normals = from.getNormalArray()) + { + osg::ref_ptr normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL); + if (normalArray) + { + normalArray->setVertexBufferObject(vbo); + to.setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); + } + } - if (osg::Vec4Array* tangents = dynamic_cast(from.getTexCoordArray(7))) - { - mSourceTangents = tangents; - osg::ref_ptr tangentArray = osg::clone(tangents, osg::CopyOp::DEEP_COPY_ALL); - tangentArray->setVertexBufferObject(vbo); - setTexCoordArray(7, tangentArray, osg::Array::BIND_PER_VERTEX); + if (osg::Vec4Array* tangents = dynamic_cast(from.getTexCoordArray(7))) + { + mSourceTangents = tangents; + osg::ref_ptr tangentArray = osg::clone(tangents, osg::CopyOp::DEEP_COPY_ALL); + tangentArray->setVertexBufferObject(vbo); + to.setTexCoordArray(7, tangentArray, osg::Array::BIND_PER_VERTEX); + } + else + mSourceTangents = NULL; } - else - mSourceTangents = NULL; } osg::ref_ptr RigGeometry::getSourceGeometry() @@ -228,7 +162,7 @@ void accumulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& mat ptrresult[14] += ptr[14] * weight; } -void RigGeometry::update(osg::NodeVisitor* nv) +void RigGeometry::cull(osg::NodeVisitor* nv) { if (!mSkeleton) { @@ -238,23 +172,24 @@ void RigGeometry::update(osg::NodeVisitor* nv) return; } - if (!mSkeleton->getActive() && mLastFrameNumber != 0) - return; - - if (mLastFrameNumber == nv->getTraversalNumber()) + if ((!mSkeleton->getActive() && mLastFrameNumber != 0) || mLastFrameNumber == nv->getTraversalNumber()) + { + nv->apply(*getGeometry(mLastFrameNumber)); return; + } mLastFrameNumber = nv->getTraversalNumber(); + osg::Geometry& geom = *getGeometry(mLastFrameNumber); mSkeleton->updateBoneMatrices(nv->getTraversalNumber()); // skinning - osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); - osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); - osg::Vec4Array* tangentSrc = mSourceTangents; + const osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); + const osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); + const osg::Vec4Array* tangentSrc = mSourceTangents; - osg::Vec3Array* positionDst = static_cast(getVertexArray()); - osg::Vec3Array* normalDst = static_cast(getNormalArray()); - osg::Vec4Array* tangentDst = static_cast(getTexCoordArray(7)); + osg::Vec3Array* positionDst = static_cast(geom.getVertexArray()); + osg::Vec3Array* normalDst = static_cast(geom.getNormalArray()); + osg::Vec4Array* tangentDst = static_cast(geom.getTexCoordArray(7)); for (Bone2VertexMap::const_iterator it = mBone2VertexMap.begin(); it != mBone2VertexMap.end(); ++it) { @@ -294,6 +229,10 @@ void RigGeometry::update(osg::NodeVisitor* nv) normalDst->dirty(); if (tangentDst) tangentDst->dirty(); + + nv->pushOntoNodePath(&geom); + nv->apply(geom); + nv->popFromNodePath(); } void RigGeometry::updateBounds(osg::NodeVisitor *nv) @@ -365,5 +304,29 @@ void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) mInfluenceMap = influenceMap; } +void RigGeometry::accept(osg::NodeVisitor &nv) +{ + if (!nv.validNodeMask(*this)) + return; + + nv.pushOntoNodePath(this); + + if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) + cull(&nv); + else if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + updateBounds(&nv); + else if (nv.getVisitorType() == osg::NodeVisitor::INTERSECTION_VISITOR) + nv.apply(*getGeometry(mLastFrameNumber)); + else + nv.apply(*this); + + nv.popFromNodePath(); +} + +osg::Geometry* RigGeometry::getGeometry(unsigned int frame) const +{ + return mGeometry[frame%2].get(); +} + } diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 39829bcb0..097e7ea69 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -13,10 +13,9 @@ namespace SceneUtil /// @brief Mesh skinning implementation. /// @note A RigGeometry may be attached directly to a Skeleton, or somewhere below a Skeleton. /// Note though that the RigGeometry ignores any transforms below the Skeleton, so the attachment point is not that important. - /// @note To avoid race conditions, the rig geometry needs to be double buffered. This can be done - /// using a FrameSwitch node that has two RigGeometry children. In the future we may want to consider implementing - /// the double buffering inside RigGeometry. - class RigGeometry : public osg::Geometry + /// @note The internal Geometry used for rendering is double buffered, this allows updates to be done in a thread safe way while + /// not compromising rendering performance. This is crucial when using osg's default threading model of DrawThreadPerContext. + class RigGeometry : public osg::Drawable { public: RigGeometry(); @@ -24,6 +23,9 @@ namespace SceneUtil META_Object(SceneUtil, RigGeometry) + // At this point compileGLObjects() remains unimplemented, hard to avoid race conditions + // and there is limited value in compiling anyway since the data will change again for the next frame + struct BoneInfluence { osg::Matrixf mInvBindMatrix; @@ -45,13 +47,15 @@ namespace SceneUtil osg::ref_ptr getSourceGeometry(); - // Called automatically by our CullCallback - void update(osg::NodeVisitor* nv); + virtual void accept(osg::NodeVisitor &nv); - // Called automatically by our UpdateCallback + private: + void cull(osg::NodeVisitor* nv); void updateBounds(osg::NodeVisitor* nv); - private: + osg::ref_ptr mGeometry[2]; + osg::Geometry* getGeometry(unsigned int frame) const; + osg::ref_ptr mSourceGeometry; osg::ref_ptr mSourceTangents; Skeleton* mSkeleton; diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 64094275c..177d700b2 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -50,7 +50,7 @@ class RigGeometrySerializer : public osgDB::ObjectWrapper { public: RigGeometrySerializer() - : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable osg::Geometry SceneUtil::RigGeometry") + : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::RigGeometry") { } }; diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 49bc5b70f..116edfdb4 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -38,8 +38,6 @@ Skeleton::Skeleton() , mNeedToUpdateBoneMatrices(true) , mActive(true) , mLastFrameNumber(0) - , mTraversedEvenFrame(false) - , mTraversedOddFrame(false) { } @@ -50,8 +48,6 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) , mNeedToUpdateBoneMatrices(true) , mActive(copy.mActive) , mLastFrameNumber(0) - , mTraversedEvenFrame(false) - , mTraversedOddFrame(false) { } @@ -115,11 +111,6 @@ void Skeleton::updateBoneMatrices(unsigned int traversalNumber) mLastFrameNumber = traversalNumber; - if (mLastFrameNumber % 2 == 0) - mTraversedEvenFrame = true; - else - mTraversedOddFrame = true; - if (mNeedToUpdateBoneMatrices) { if (mRootBone.get()) @@ -144,18 +135,14 @@ bool Skeleton::getActive() const void Skeleton::markDirty() { - mTraversedEvenFrame = false; - mTraversedOddFrame = false; + mLastFrameNumber = 0; mBoneCache.clear(); mBoneCacheInit = false; } void Skeleton::traverse(osg::NodeVisitor& nv) { - 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 && mTraversedEvenFrame && mTraversedOddFrame) + if (!getActive() && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && mLastFrameNumber != 0) return; osg::Group::traverse(nv); } diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index 542471ff1..245e3522c 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -74,8 +74,6 @@ namespace SceneUtil bool mActive; unsigned int mLastFrameNumber; - bool mTraversedEvenFrame; - bool mTraversedOddFrame; }; } From 4c5992a0d5b58ca18ed00a116f33d78b9b12aeec Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 21:45:18 +0200 Subject: [PATCH 11/44] Warn if removing a node fails --- apps/openmw/mwrender/animation.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 22bafaa71..df9b8545a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -182,7 +182,10 @@ namespace void remove() { for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) - it->second->removeChild(it->first); + { + if (!it->second->removeChild(it->first)) + std::cerr << "error removing " << it->first->getName() << std::endl; + } } protected: From f1ebb129c139690450a74abbc7ae46674dcaef62 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 22:01:50 +0200 Subject: [PATCH 12/44] Fix ShaderVisitor to deal with the fact RigGeometry no longer derives from Geometry --- components/shader/shadervisitor.cpp | 81 +++++++++++++++-------------- components/shader/shadervisitor.hpp | 1 + 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 2d5fdfb39..2c0b9f0e3 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -248,6 +248,9 @@ namespace Shader void ShaderVisitor::createProgram(const ShaderRequirements &reqs) { + if (!reqs.mShaderRequired && !mForceShaders) + return; + osg::Node& node = *reqs.mNode; osg::StateSet* writableStateSet = NULL; if (mAllowedToModifyStateSets) @@ -305,6 +308,36 @@ namespace Shader } } + bool ShaderVisitor::adjustGeometry(osg::Geometry& sourceGeometry, const ShaderRequirements& reqs) + { + bool useShader = reqs.mShaderRequired || mForceShaders; + bool generateTangents = reqs.mTexStageRequiringTangents != -1; + bool changed = false; + + if (mAllowedToModifyStateSets && (useShader || generateTangents)) + { + // make sure that all UV sets are there + for (std::map::const_iterator it = reqs.mTextures.begin(); it != reqs.mTextures.end(); ++it) + { + if (sourceGeometry.getTexCoordArray(it->first) == NULL) + { + sourceGeometry.setTexCoordArray(it->first, sourceGeometry.getTexCoordArray(0)); + changed = true; + } + } + + if (generateTangents) + { + osg::ref_ptr generator (new osgUtil::TangentSpaceGenerator); + generator->generate(&sourceGeometry, reqs.mTexStageRequiringTangents); + + sourceGeometry.setTexCoordArray(7, generator->getTangentArray(), osg::Array::BIND_PER_VERTEX); + changed = true; + } + } + return changed; + } + void ShaderVisitor::apply(osg::Geometry& geometry) { bool needPop = (geometry.getStateSet() != NULL); @@ -318,43 +351,9 @@ namespace Shader { const ShaderRequirements& reqs = mRequirements.back(); - bool useShader = reqs.mShaderRequired || mForceShaders; - bool generateTangents = reqs.mTexStageRequiringTangents != -1; - - if (mAllowedToModifyStateSets && (useShader || generateTangents)) - { - osg::ref_ptr sourceGeometry = &geometry; - SceneUtil::RigGeometry* rig = dynamic_cast(&geometry); - if (rig) - sourceGeometry = rig->getSourceGeometry(); - - bool requiresSetGeometry = false; + adjustGeometry(geometry, reqs); - // make sure that all UV sets are there - for (std::map::const_iterator it = reqs.mTextures.begin(); it != reqs.mTextures.end(); ++it) - { - if (sourceGeometry->getTexCoordArray(it->first) == NULL) - { - sourceGeometry->setTexCoordArray(it->first, sourceGeometry->getTexCoordArray(0)); - requiresSetGeometry = true; - } - } - - if (generateTangents) - { - osg::ref_ptr generator (new osgUtil::TangentSpaceGenerator); - generator->generate(sourceGeometry, reqs.mTexStageRequiringTangents); - - sourceGeometry->setTexCoordArray(7, generator->getTangentArray(), osg::Array::BIND_PER_VERTEX); - requiresSetGeometry = true; - } - - if (rig && requiresSetGeometry) - rig->setSourceGeometry(sourceGeometry); - } - - if (useShader) - createProgram(reqs); + createProgram(reqs); } if (needPop) @@ -375,8 +374,14 @@ namespace Shader if (!mRequirements.empty()) { const ShaderRequirements& reqs = mRequirements.back(); - if (reqs.mShaderRequired || mForceShaders) - createProgram(reqs); + createProgram(reqs); + + if (SceneUtil::RigGeometry* rig = dynamic_cast(&drawable)) + { + osg::ref_ptr sourceGeometry = rig->getSourceGeometry(); + if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) + rig->setSourceGeometry(sourceGeometry); + } } if (needPop) diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index 83f28e063..cb0538d9d 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -99,6 +99,7 @@ namespace Shader std::string mDefaultFsTemplate; void createProgram(const ShaderRequirements& reqs); + bool adjustGeometry(osg::Geometry& sourceGeometry, const ShaderRequirements& reqs); }; } From 5d524a6a10672c3800f5ac396272635ea1cc09a8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 22:56:09 +0200 Subject: [PATCH 13/44] Add custom version of MorphGeometry replacing osgAnimation Double buffering, custom bounding box and the update in the cull visitor (instead of update) are now all handled internally rather than needing hacks and/or callbacks. --- CMakeLists.txt | 2 +- components/CMakeLists.txt | 2 +- components/nifosg/controller.cpp | 9 +- components/nifosg/controller.hpp | 7 +- components/nifosg/nifloader.cpp | 186 +++--------------------- components/sceneutil/clone.cpp | 38 +---- components/sceneutil/morphgeometry.cpp | 187 +++++++++++++++++++++++++ components/sceneutil/morphgeometry.hpp | 81 +++++++++++ components/sceneutil/serialize.cpp | 15 +- components/shader/shadervisitor.cpp | 9 +- 10 files changed, 308 insertions(+), 228 deletions(-) create mode 100644 components/sceneutil/morphgeometry.cpp create mode 100644 components/sceneutil/morphgeometry.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ad2c64b6e..a78eac572 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,7 +207,7 @@ if(NOT HAVE_STDINT_H) endif() -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) set(USED_OSG_PLUGINS diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6430dbfce..88de17903 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -49,7 +49,7 @@ add_component_dir (shader ) add_component_dir (sceneutil - clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller + clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer ) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 87a0b830e..262966e95 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -6,11 +6,10 @@ #include #include -#include - #include #include +#include #include "userdata.hpp" @@ -188,7 +187,7 @@ GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) { - osgAnimation::MorphGeometry* morphGeom = static_cast(drawable); + SceneUtil::MorphGeometry* morphGeom = static_cast(drawable); if (hasInput()) { if (mKeyFrames.size() <= 1) @@ -202,7 +201,7 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable val = it->interpKey(input); val = std::max(0.f, std::min(1.f, val)); - osgAnimation::MorphGeometry::MorphTarget& target = morphGeom->getMorphTarget(i); + SceneUtil::MorphGeometry::MorphTarget& target = morphGeom->getMorphTarget(i); if (target.getWeight() != val) { target.setWeight(val); @@ -210,8 +209,6 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable } } } - - // morphGeometry::transformSoftwareMethod() done in cull callback i.e. only for visible morph geometries } UVController::UVController() diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 5fbb172f9..0e87af44f 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -31,11 +31,6 @@ namespace osgParticle class Emitter; } -namespace osgAnimation -{ - class MorphGeometry; -} - namespace NifOsg { @@ -172,7 +167,7 @@ namespace NifOsg virtual float getMaximum() const; }; - /// Must be set on an osgAnimation::MorphGeometry. + /// Must be set on a SceneUtil::MorphGeometry. class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller { public: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6b603cc9e..8810f171a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -13,9 +13,6 @@ #include #include -// skel -#include - // particle #include #include @@ -39,6 +36,7 @@ #include #include #include +#include #include "particle.hpp" #include "userdata.hpp" @@ -83,35 +81,6 @@ namespace collectDrawableProperties(nifNode->parent, out); } - class FrameSwitch : public osg::Group - { - public: - FrameSwitch() - { - } - - FrameSwitch(const FrameSwitch& copy, const osg::CopyOp& copyop) - : osg::Group(copy, copyop) - { - } - - META_Object(NifOsg, FrameSwitch) - - virtual void traverse(osg::NodeVisitor& nv) - { - if (nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN && nv.getVisitorType() != osg::NodeVisitor::UPDATE_VISITOR) - osg::Group::traverse(nv); - else - { - for (unsigned int i=0; iaccept(nv); - } - } - } - }; - // 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. @@ -154,70 +123,6 @@ namespace } }; - struct UpdateMorphGeometry : public osg::Drawable::CullCallback - { - UpdateMorphGeometry() - : mLastFrameNumber(0) - { - } - - UpdateMorphGeometry(const UpdateMorphGeometry& copy, const osg::CopyOp& copyop) - : osg::Drawable::CullCallback(copy, copyop) - , mLastFrameNumber(0) - { - } - - META_Object(NifOsg, UpdateMorphGeometry) - - virtual bool cull(osg::NodeVisitor* nv, osg::Drawable * drw, osg::State *) const - { - osgAnimation::MorphGeometry* geom = static_cast(drw); - if (!geom) - return false; - - if (mLastFrameNumber == nv->getTraversalNumber()) - return false; - mLastFrameNumber = nv->getTraversalNumber(); - - geom->transformSoftwareMethod(); - return false; - } - - private: - mutable unsigned int mLastFrameNumber; - }; - - // Callback to return a static bounding box for a MorphGeometry. The idea is to not recalculate the bounding box - // every time the morph weights change. To do so we return a maximum containing box that is big enough for all possible combinations of morph targets. - class StaticBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback - { - public: - StaticBoundingBoxCallback() - { - } - - StaticBoundingBoxCallback(const osg::BoundingBox& bounds) - : mBoundingBox(bounds) - { - } - - StaticBoundingBoxCallback(const StaticBoundingBoxCallback& copy, const osg::CopyOp& copyop) - : osg::Drawable::ComputeBoundingBoxCallback(copy, copyop) - , mBoundingBox(copy.mBoundingBox) - { - } - - META_Object(NifOsg, StaticBoundingBoxCallback) - - virtual osg::BoundingBox computeBound(const osg::Drawable&) const - { - return mBoundingBox; - } - - private: - osg::BoundingBox mBoundingBox; - }; - void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) { for(size_t i = 0;i < tk->list.size();i++) @@ -1107,108 +1012,49 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr geometry; + osg::ref_ptr drawable; for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) continue; if(ctrl->recType == Nif::RC_NiGeomMorpherController) { - geometry = handleMorphGeometry(static_cast(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags); + drawable = handleMorphGeometry(static_cast(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags); osg::ref_ptr morphctrl = new GeomMorpherController( static_cast(ctrl.getPtr())->data.getPtr()); setupController(ctrl.getPtr(), morphctrl, animflags); - geometry->setUpdateCallback(morphctrl); + drawable->setUpdateCallback(morphctrl); break; } } - if (!geometry.get()) + if (!drawable.get()) { - geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); + osg::ref_ptr geom (new osg::Geometry); + drawable = geom; + triShapeToGeometry(triShape, geom, parentNode, composite, boundTextures, animflags); } - geometry->setName(triShape->name); - - 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 frameswitch = new FrameSwitch; + drawable->setName(triShape->name); - osg::ref_ptr geom2 = osg::clone(geometry.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES); - frameswitch->addChild(geometry); - frameswitch->addChild(geom2); - - parentNode->addChild(frameswitch); - } - else - parentNode->addChild(geometry); + parentNode->addChild(drawable); } - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; - morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); - // No normals available in the MorphData - morphGeom->setMorphNormals(false); - - morphGeom->setUpdateCallback(NULL); - morphGeom->setCullCallback(new UpdateMorphGeometry); - morphGeom->setUseVertexBufferObjects(true); + osg::ref_ptr morphGeom = new SceneUtil::MorphGeometry; - triShapeToGeometry(triShape, morphGeom, parentNode, composite, boundTextures, animflags); - - morphGeom->getOrCreateVertexBufferObject()->setUsage(GL_DYNAMIC_DRAW_ARB); + osg::ref_ptr sourceGeometry (new osg::Geometry); + triShapeToGeometry(triShape, sourceGeometry, parentNode, composite, boundTextures, animflags); + morphGeom->setSourceGeometry(sourceGeometry); const std::vector& morphs = morpher->data.getPtr()->mMorphs; if (morphs.empty()) return morphGeom; // Note we are not interested in morph 0, which just contains the original vertices for (unsigned int i = 1; i < morphs.size(); ++i) - { - osg::ref_ptr morphTarget = new osg::Geometry; - morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); - morphGeom->addMorphTarget(morphTarget, 0.f); - } - - // build the bounding box containing all possible morph combinations - - std::vector vertBounds(morphs[0].mVertices.size()); - - // Since we don't know what combinations of morphs are being applied we need to keep track of a bounding box for each vertex. - // The minimum/maximum of the box is the minimum/maximum offset the vertex can have from its starting position. - - // Start with zero offsets which will happen when no morphs are applied. - for (unsigned int i=0; igetBound(); - - // Now set up the callback so that we get properly enlarged bounds if/when the mesh starts animating - morphGeom->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(box)); + morphGeom->addMorphTarget(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0]), 0.f); return morphGeom; } diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 738c7a30d..08f36cfcf 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include @@ -49,46 +49,12 @@ namespace SceneUtil { if (const osgParticle::ParticleSystem* partsys = dynamic_cast(drawable)) return operator()(partsys); - if (dynamic_cast(drawable)) - { - 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: - - if ((copyop.getCopyFlags() & osg::CopyOp::DEEP_COPY_ARRAYS)) - { - if (_useVertexBufferObjects) - { - // copying of arrays doesn't set up buffer objects so we'll need to force - // Geometry to assign these, we'll do this by switching off VBO's then renabling them. - setUseVertexBufferObjects(false); - setUseVertexBufferObjects(true); - } - } - - In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, - causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. - 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); - return cloned; - } - if (dynamic_cast(drawable)) + if (dynamic_cast(drawable) || dynamic_cast(drawable)) { return osg::clone(drawable, *this); } - return osg::CopyOp::operator()(drawable); } diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp new file mode 100644 index 000000000..5d55e75ec --- /dev/null +++ b/components/sceneutil/morphgeometry.cpp @@ -0,0 +1,187 @@ +#include "morphgeometry.hpp" + +#include + +namespace SceneUtil +{ + +MorphGeometry::MorphGeometry() + : mLastFrameNumber(0) + , mDirty(true) + , mMorphedBoundingBox(false) +{ + +} + +MorphGeometry::MorphGeometry(const MorphGeometry ©, const osg::CopyOp ©op) + : osg::Drawable(copy, copyop) + , mMorphTargets(copy.mMorphTargets) + , mLastFrameNumber(0) + , mDirty(true) + , mMorphedBoundingBox(false) +{ + setSourceGeometry(copy.getSourceGeometry()); +} + +void MorphGeometry::setSourceGeometry(osg::ref_ptr sourceGeom) +{ + mSourceGeometry = sourceGeom; + + for (unsigned int i=0; i<2; ++i) + { + mGeometry[i] = new osg::Geometry(*mSourceGeometry, osg::CopyOp::SHALLOW_COPY); + + osg::Geometry& from = *mSourceGeometry; + osg::Geometry& to = *mGeometry[i]; + to.setSupportsDisplayList(false); + to.setUseVertexBufferObjects(true); + to.setCullingActive(false); // make sure to disable culling since that's handled by this class + + // vertices are modified every frame, so we need to deep copy them. + // assign a dedicated VBO to make sure that modifications don't interfere with source geometry's VBO. + osg::ref_ptr vbo (new osg::VertexBufferObject); + vbo->setUsage(GL_DYNAMIC_DRAW_ARB); + + osg::ref_ptr vertexArray = osg::clone(from.getVertexArray(), osg::CopyOp::DEEP_COPY_ALL); + if (vertexArray) + { + vertexArray->setVertexBufferObject(vbo); + to.setVertexArray(vertexArray); + } + } +} + +void MorphGeometry::addMorphTarget(osg::Vec3Array *offsets, float weight) +{ + mMorphTargets.push_back(MorphTarget(offsets, weight)); + mMorphedBoundingBox = false; + dirty(); +} + +void MorphGeometry::dirty() +{ + mDirty = true; + if (!mMorphedBoundingBox) + { + _boundingBoxComputed = false; + dirtyBound(); + } +} + +osg::ref_ptr MorphGeometry::getSourceGeometry() const +{ + return mSourceGeometry; +} + +void MorphGeometry::accept(osg::NodeVisitor &nv) +{ + if (!nv.validNodeMask(*this)) + return; + + nv.pushOntoNodePath(this); + + if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) + cull(&nv); + else if (nv.getVisitorType() == osg::NodeVisitor::INTERSECTION_VISITOR) + nv.apply(*getGeometry(mLastFrameNumber)); + else + nv.apply(*this); + + nv.popFromNodePath(); +} + +osg::BoundingBox MorphGeometry::computeBoundingBox() const +{ + bool anyMorphTarget = false; + for (unsigned int i=0; i 0) + { + anyMorphTarget = true; + break; + } + + // before the MorphGeometry has started animating, we will use a regular bounding box (this is required + // for correct object placements, which uses the bounding box) + if (!mMorphedBoundingBox && !anyMorphTarget) + { + return mSourceGeometry->getBoundingBox(); + } + // once it animates, use a bounding box that encompasses all possible animations so as to avoid recalculating + else + { + mMorphedBoundingBox = true; + + osg::Vec3Array& sourceVerts = *static_cast(mSourceGeometry->getVertexArray()); + std::vector vertBounds(sourceVerts.size()); + + // Since we don't know what combinations of morphs are being applied we need to keep track of a bounding box for each vertex. + // The minimum/maximum of the box is the minimum/maximum offset the vertex can have from its starting position. + + // Start with zero offsets which will happen when no morphs are applied. + for (unsigned int i=0; igetTraversalNumber() || !mDirty) + { + nv->apply(*getGeometry(mLastFrameNumber)); + return; + } + + mDirty = false; + mLastFrameNumber = nv->getTraversalNumber(); + osg::Geometry& geom = *getGeometry(mLastFrameNumber); + + const osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); + osg::Vec3Array* positionDst = static_cast(geom.getVertexArray()); + assert(positionSrc->size() == positionDst->size()); + for (unsigned int vertex=0; vertexsize(); ++vertex) + (*positionDst)[vertex] = (*positionSrc)[vertex]; + + for (unsigned int i=0; isize(); ++vertex) + (*positionDst)[vertex] += (*offsets)[vertex] * weight; + } + + positionDst->dirty(); + + nv->pushOntoNodePath(&geom); + nv->apply(geom); + nv->popFromNodePath(); +} + +osg::Geometry* MorphGeometry::getGeometry(unsigned int frame) const +{ + return mGeometry[frame%2]; +} + + +} diff --git a/components/sceneutil/morphgeometry.hpp b/components/sceneutil/morphgeometry.hpp new file mode 100644 index 000000000..1afef1895 --- /dev/null +++ b/components/sceneutil/morphgeometry.hpp @@ -0,0 +1,81 @@ +#ifndef OPENMW_COMPONENTS_MORPHGEOMETRY_H +#define OPENMW_COMPONENTS_MORPHGEOMETRY_H + +#include + +namespace SceneUtil +{ + + /// @brief Vertex morphing implementation. + /// @note The internal Geometry used for rendering is double buffered, this allows updates to be done in a thread safe way while + /// not compromising rendering performance. This is crucial when using osg's default threading model of DrawThreadPerContext. + class MorphGeometry : public osg::Drawable + { + public: + MorphGeometry(); + MorphGeometry(const MorphGeometry& copy, const osg::CopyOp& copyop); + + META_Object(SceneUtil, MorphGeometry) + + /// Initialize this geometry from the source geometry. + /// @note The source geometry will not be modified. + void setSourceGeometry(osg::ref_ptr sourceGeom); + + class MorphTarget + { + protected: + osg::ref_ptr mOffsets; + float mWeight; + public: + MorphTarget(osg::Vec3Array* offsets, float w = 1.0) : mOffsets(offsets), mWeight(w) {} + void setWeight(float weight) { mWeight = weight; } + float getWeight() const { return mWeight; } + osg::Vec3Array* getOffsets() { return mOffsets.get(); } + const osg::Vec3Array* getOffsets() const { return mOffsets.get(); } + void setOffsets(osg::Vec3Array* offsets) { mOffsets = offsets; } + }; + + typedef std::vector MorphTargetList; + + virtual void addMorphTarget( osg::Vec3Array* offsets, float weight = 1.0 ); + + /** Set the MorphGeometry dirty.*/ + void dirty(); + + /** Get the list of MorphTargets.*/ + const MorphTargetList& getMorphTargetList() const { return mMorphTargets; } + + /** Get the list of MorphTargets. Warning if you modify this array you will have to call dirty() */ + MorphTargetList& getMorphTargetList() { return mMorphTargets; } + + /** Return the \c MorphTarget at position \c i.*/ + inline const MorphTarget& getMorphTarget( unsigned int i ) const { return mMorphTargets[i]; } + + /** Return the \c MorphTarget at position \c i.*/ + inline MorphTarget& getMorphTarget( unsigned int i ) { return mMorphTargets[i]; } + + osg::ref_ptr getSourceGeometry() const; + + virtual void accept(osg::NodeVisitor &nv); + + virtual osg::BoundingBox computeBoundingBox() const; + + private: + void cull(osg::NodeVisitor* nv); + + MorphTargetList mMorphTargets; + + osg::ref_ptr mSourceGeometry; + + osg::ref_ptr mGeometry[2]; + osg::Geometry* getGeometry(unsigned int frame) const; + + unsigned int mLastFrameNumber; + bool mDirty; // Have any morph targets changed? + + mutable bool mMorphedBoundingBox; + }; + +} + +#endif diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 177d700b2..ab0321532 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace SceneUtil { @@ -37,20 +38,20 @@ public: } }; -class FrameSwitchSerializer : public osgDB::ObjectWrapper +class RigGeometrySerializer : public osgDB::ObjectWrapper { public: - FrameSwitchSerializer() - : osgDB::ObjectWrapper(createInstanceFunc, "NifOsg::FrameSwitch", "osg::Object osg::Node osg::Group NifOsg::FrameSwitch") + RigGeometrySerializer() + : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::RigGeometry") { } }; -class RigGeometrySerializer : public osgDB::ObjectWrapper +class MorphGeometrySerializer : public osgDB::ObjectWrapper { public: - RigGeometrySerializer() - : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::RigGeometry") + MorphGeometrySerializer() + : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::MorphGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::MorphGeometry") { } }; @@ -95,8 +96,8 @@ void registerSerializers() osgDB::ObjectWrapperManager* mgr = osgDB::Registry::instance()->getObjectWrapperManager(); mgr->addWrapper(new PositionAttitudeTransformSerializer); mgr->addWrapper(new SkeletonSerializer); - mgr->addWrapper(new FrameSwitchSerializer); mgr->addWrapper(new RigGeometrySerializer); + mgr->addWrapper(new MorphGeometrySerializer); mgr->addWrapper(new LightManagerSerializer); mgr->addWrapper(new CameraRelativeTransformSerializer); diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 2c0b9f0e3..9b3876d6c 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "shadermanager.hpp" @@ -376,12 +377,18 @@ namespace Shader const ShaderRequirements& reqs = mRequirements.back(); createProgram(reqs); - if (SceneUtil::RigGeometry* rig = dynamic_cast(&drawable)) + if (auto rig = dynamic_cast(&drawable)) { osg::ref_ptr sourceGeometry = rig->getSourceGeometry(); if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) rig->setSourceGeometry(sourceGeometry); } + else if (auto morph = dynamic_cast(&drawable)) + { + osg::ref_ptr sourceGeometry = morph->getSourceGeometry(); + if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) + morph->setSourceGeometry(sourceGeometry); + } } if (needPop) From 4bef8260abcfe137bd206262e980b0249d041143 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 23:02:19 +0200 Subject: [PATCH 14/44] Add const qualifiers --- components/sceneutil/morphgeometry.cpp | 2 +- components/sceneutil/riggeometry.cpp | 6 +++--- components/sceneutil/riggeometry.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 5d55e75ec..4c53b68a5 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -31,7 +31,7 @@ void MorphGeometry::setSourceGeometry(osg::ref_ptr sourceGeom) { mGeometry[i] = new osg::Geometry(*mSourceGeometry, osg::CopyOp::SHALLOW_COPY); - osg::Geometry& from = *mSourceGeometry; + const osg::Geometry& from = *mSourceGeometry; osg::Geometry& to = *mGeometry[i]; to.setSupportsDisplayList(false); to.setUseVertexBufferObjects(true); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index ec01f62d0..f3eea1bbd 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -35,7 +35,7 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) for (unsigned int i=0; i<2; ++i) { - osg::Geometry& from = *sourceGeometry; + const osg::Geometry& from = *sourceGeometry; mGeometry[i] = new osg::Geometry(from, osg::CopyOp::SHALLOW_COPY); osg::Geometry& to = *mGeometry[i]; to.setSupportsDisplayList(false); @@ -54,7 +54,7 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) to.setVertexArray(vertexArray); } - if (osg::Array* normals = from.getNormalArray()) + if (const osg::Array* normals = from.getNormalArray()) { osg::ref_ptr normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL); if (normalArray) @@ -64,7 +64,7 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) } } - if (osg::Vec4Array* tangents = dynamic_cast(from.getTexCoordArray(7))) + if (const osg::Vec4Array* tangents = dynamic_cast(from.getTexCoordArray(7))) { mSourceTangents = tangents; osg::ref_ptr tangentArray = osg::clone(tangents, osg::CopyOp::DEEP_COPY_ALL); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 097e7ea69..638f53679 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -57,7 +57,7 @@ namespace SceneUtil osg::Geometry* getGeometry(unsigned int frame) const; osg::ref_ptr mSourceGeometry; - osg::ref_ptr mSourceTangents; + osg::ref_ptr mSourceTangents; Skeleton* mSkeleton; osg::ref_ptr mGeomToSkelMatrix; From 5e790b567e460de29bea43ec5410822db58a6e57 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 22:12:40 +0000 Subject: [PATCH 15/44] Fix node path issue Needs to be set so that the 'cullingActive' flag of the node path's end can be checked --- components/sceneutil/morphgeometry.cpp | 5 ++++- components/sceneutil/riggeometry.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 4c53b68a5..98e5a92bc 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -147,7 +147,10 @@ void MorphGeometry::cull(osg::NodeVisitor *nv) { if (mLastFrameNumber == nv->getTraversalNumber() || !mDirty) { - nv->apply(*getGeometry(mLastFrameNumber)); + osg::Geometry& geom = *getGeometry(mLastFrameNumber); + nv->pushOntoNodePath(&geom); + nv->apply(geom); + nv->popFromNodePath(); return; } diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index f3eea1bbd..f52bca80c 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -174,7 +174,10 @@ void RigGeometry::cull(osg::NodeVisitor* nv) if ((!mSkeleton->getActive() && mLastFrameNumber != 0) || mLastFrameNumber == nv->getTraversalNumber()) { - nv->apply(*getGeometry(mLastFrameNumber)); + osg::Geometry& geom = *getGeometry(mLastFrameNumber); + nv->pushOntoNodePath(&geom); + nv->apply(geom); + nv->popFromNodePath(); return; } mLastFrameNumber = nv->getTraversalNumber(); From 0060e457a60cc691a2532eeb16d005b13152c87d Mon Sep 17 00:00:00 2001 From: John Date: Sat, 2 Sep 2017 16:19:18 +0200 Subject: [PATCH 16/44] [General] Add .desktop file for Server Browser --- CMakeLists.txt | 5 +++++ files/tes3mp-browser.desktop | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 files/tes3mp-browser.desktop diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f6889515..c2621fee7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -357,6 +357,8 @@ if (NOT WIN32 AND NOT APPLE) "${OpenMW_BINARY_DIR}/openmw.desktop") configure_file(${OpenMW_SOURCE_DIR}/files/openmw.appdata.xml "${OpenMW_BINARY_DIR}/openmw.appdata.xml") + configure_file(${OpenMW_SOURCE_DIR}/files/tes3mp-browser.desktop + "${OpenMW_BINARY_DIR}/tes3mp-browser.desktop") configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.desktop "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() @@ -437,6 +439,9 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/metainfo" COMPONENT "openmw") + IF(BUILD_BROWSER) + INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-browser.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "browser") + ENDIF(BUILD_BROWSER) IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs") diff --git a/files/tes3mp-browser.desktop b/files/tes3mp-browser.desktop new file mode 100644 index 000000000..caf8d9e93 --- /dev/null +++ b/files/tes3mp-browser.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Application +Name=TES3MP Server Browser +GenericName=Server Browser +Comment=Multiplayer extension for TES3. +Keywords=Morrowind;Multiplayer;Server Browser;TES;openmw; +TryExec=tes3mp-browser +Exec=tes3mp-browser +Icon=openmw +Categories=Game;RolePlaying; From e0ffc94f3e7fc9922bda949b7d0184071e5ef91b Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 2 Sep 2017 18:07:12 -0500 Subject: [PATCH 17/44] Fix OpenMW-CS internal name --- apps/opencs/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0a146dc06..fc8930b71 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -199,7 +199,7 @@ if(APPLE) RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" OUTPUT_NAME ${OPENCS_BUNDLE_NAME} MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" - MACOSX_BUNDLE_BUNDLE_NAME "OpenCS" + MACOSX_BUNDLE_BUNDLE_NAME "OpenMW-CS" MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION} MACOSX_BUNDLE_BUNDLE_VERSION ${OPENMW_VERSION} From 10fff499a2103b2c0ca6e15172155e2b61a245b5 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 2 Sep 2017 19:02:55 -0500 Subject: [PATCH 18/44] Adding that Reflect Actors can be toggled in the video panel --- docs/source/reference/modding/settings/water.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/reference/modding/settings/water.rst b/docs/source/reference/modding/settings/water.rst index 2344222e5..a1c6c2068 100644 --- a/docs/source/reference/modding/settings/water.rst +++ b/docs/source/reference/modding/settings/water.rst @@ -56,7 +56,7 @@ Enabling this feature results in better visuals, and a marginally lower frame ra This setting has no effect if the shader setting is false. -This setting can be toggled with the Refraction button in the Water tab of the Video panel of the Options menu. +This setting can be toggled with the 'Refraction' button in the Water tab of the Video panel of the Options menu. reflect actors -------------- @@ -68,6 +68,8 @@ reflect actors This setting controls whether or not NPCs and creatures are drawn in water reflections. Setting this to true will enable actors in reflections and increase realism with a likely decrease in performance. +This setting can be toggled with the 'Reflect actors' button in the Water tab of the Video panel of the Options menu. + small feature culling pixel size -------------------------------- From d9046281032f659e40bd9ac321e8780744e39f0b Mon Sep 17 00:00:00 2001 From: Koncord Date: Sun, 3 Sep 2017 18:53:45 +0800 Subject: [PATCH 19/44] [General] Avoid limitation of 512 symbols in RakString Ctor --- components/openmw-mp/Packets/BasePacket.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/openmw-mp/Packets/BasePacket.hpp b/components/openmw-mp/Packets/BasePacket.hpp index 8dd964a03..e02d9ed02 100644 --- a/components/openmw-mp/Packets/BasePacket.hpp +++ b/components/openmw-mp/Packets/BasePacket.hpp @@ -80,11 +80,17 @@ namespace mwmp { if (write) { - RakNet::RakString rstr("%s", str.c_str()); if (compress) - rstr.SerializeCompressed(bs); + { + if (!str.empty()) + RakNet::RakString::SerializeCompressed(str.c_str(), bs); + } else + { + RakNet::RakString rstr; + rstr = str.c_str(); bs->Write(rstr); + } } else { From 2e58024f1c8adc44d02d42a4c2d20a31073d2ce4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 3 Sep 2017 16:02:40 +0200 Subject: [PATCH 20/44] Fix intersections with Rig/MorphGeometry, was caused by an issue in the LineSegmentIntersector not respecting the cullingActive flag of a drawable. --- components/sceneutil/morphgeometry.cpp | 7 +++++-- components/sceneutil/morphgeometry.hpp | 2 ++ components/sceneutil/riggeometry.cpp | 7 +++++-- components/sceneutil/riggeometry.hpp | 2 ++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 98e5a92bc..2ffbace3b 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -82,14 +82,17 @@ void MorphGeometry::accept(osg::NodeVisitor &nv) if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) cull(&nv); - else if (nv.getVisitorType() == osg::NodeVisitor::INTERSECTION_VISITOR) - nv.apply(*getGeometry(mLastFrameNumber)); else nv.apply(*this); nv.popFromNodePath(); } +void MorphGeometry::accept(osg::PrimitiveFunctor& func) const +{ + getGeometry(mLastFrameNumber)->accept(func); +} + osg::BoundingBox MorphGeometry::computeBoundingBox() const { bool anyMorphTarget = false; diff --git a/components/sceneutil/morphgeometry.hpp b/components/sceneutil/morphgeometry.hpp index 1afef1895..122c1456c 100644 --- a/components/sceneutil/morphgeometry.hpp +++ b/components/sceneutil/morphgeometry.hpp @@ -57,6 +57,8 @@ namespace SceneUtil osg::ref_ptr getSourceGeometry() const; virtual void accept(osg::NodeVisitor &nv); + virtual bool supports(const osg::PrimitiveFunctor&) const { return true; } + virtual void accept(osg::PrimitiveFunctor&) const; virtual osg::BoundingBox computeBoundingBox() const; diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index f52bca80c..7f148cf5e 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -318,14 +318,17 @@ void RigGeometry::accept(osg::NodeVisitor &nv) cull(&nv); else if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) updateBounds(&nv); - else if (nv.getVisitorType() == osg::NodeVisitor::INTERSECTION_VISITOR) - nv.apply(*getGeometry(mLastFrameNumber)); else nv.apply(*this); nv.popFromNodePath(); } +void RigGeometry::accept(osg::PrimitiveFunctor& func) const +{ + getGeometry(mLastFrameNumber)->accept(func); +} + osg::Geometry* RigGeometry::getGeometry(unsigned int frame) const { return mGeometry[frame%2].get(); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 638f53679..64f4bf312 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -48,6 +48,8 @@ namespace SceneUtil osg::ref_ptr getSourceGeometry(); virtual void accept(osg::NodeVisitor &nv); + virtual bool supports(const osg::PrimitiveFunctor&) const { return true; } + virtual void accept(osg::PrimitiveFunctor&) const; private: void cull(osg::NodeVisitor* nv); From f5e23d5fc6ec89327b78422dcd418ba8616a1f5a Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 4 Sep 2017 04:03:02 +0800 Subject: [PATCH 21/44] [General] Empty strings should be sent too --- components/openmw-mp/Packets/BasePacket.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/components/openmw-mp/Packets/BasePacket.hpp b/components/openmw-mp/Packets/BasePacket.hpp index e02d9ed02..03b912366 100644 --- a/components/openmw-mp/Packets/BasePacket.hpp +++ b/components/openmw-mp/Packets/BasePacket.hpp @@ -81,10 +81,7 @@ namespace mwmp if (write) { if (compress) - { - if (!str.empty()) - RakNet::RakString::SerializeCompressed(str.c_str(), bs); - } + RakNet::RakString::SerializeCompressed(str.c_str(), bs); else { RakNet::RakString rstr; From ccb15cc09e9ab61466e9a11621c4217da4400554 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 4 Sep 2017 15:13:05 +0300 Subject: [PATCH 22/44] [Client] When players die, make guards willing to arrest them again --- apps/openmw/mwgui/jailscreen.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 31 ++++++++++++++++++- apps/openmw/mwmechanics/aipursue.cpp | 15 +++++++++ apps/openmw/mwmp/LocalPlayer.cpp | 2 ++ .../player/ProcessorPlayerResurrect.hpp | 6 ++++ components/openmw-mp/Base/BasePlayer.hpp | 2 ++ 6 files changed, 56 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 0874f5fdf..ecd6d18f0 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -129,7 +129,7 @@ namespace MWGui Disable increases for Security and Sneak when using ignoreJailSkillIncreases */ if (mwmp::Main::get().getLocalPlayer()->ignoreJailSkillIncreases) - value.setBase(value.getBase() - 1); + value.setBase(std::max(0, value.getBase()-1)); else if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) /* End of tes3mp change (minor) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 879798a44..6e2f068af 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1065,7 +1065,18 @@ namespace MWMechanics && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr)) { static const int iCrimeThresholdMultiplier = esmStore.get().find("iCrimeThresholdMultiplier")->getInt(); - if (player.getClass().getNpcStats(player).getBounty() >= cutoff * iCrimeThresholdMultiplier) + + /* + Start of tes3mp change (major) + + Only attack players based on their high bounty if they haven't died since the last + time an attempt was made to arrest them + */ + if (player.getClass().getNpcStats(player).getBounty() >= cutoff * iCrimeThresholdMultiplier + && !mwmp::Main::get().getLocalPlayer()->diedSinceArrestAttempt) + /* + End of tes3mp change (major) + */ { MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player); creatureStats.setHitAttemptActorId(player.getClass().getCreatureStats(player).getActorId()); // Stops the guard from quitting combat if player is unreachable @@ -1096,6 +1107,24 @@ namespace MWMechanics // Update witness crime id npcStats.setCrimeId(-1); } + /* + Start of tes3mp addition + + If the player has died, stop combat with them as though they had + paid their bounty + */ + else if (mwmp::Main::get().getLocalPlayer()->diedSinceArrestAttempt) + { + if (creatureStats.getAiSequence().isInCombat(player)) + { + creatureStats.getAiSequence().stopCombat(); + creatureStats.setAttacked(false); + creatureStats.setAlarmed(false); + } + } + /* + End of tes3mp addition + */ } } } diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 2a375534e..50a68c8e6 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -13,7 +13,10 @@ Include additional headers for multiplayer purposes */ +#include #include "../mwgui/windowmanagerimp.hpp" +#include "../mwmp/Main.hpp" +#include "../mwmp/LocalPlayer.hpp" /* End of tes3mp addition */ @@ -81,6 +84,18 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte if (pathTo(actor, dest, duration, 100)) { target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached + + /* + Start of tes3mp addition + + Record that the player has not died since the last attempt to arrest them + */ + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "After being pursued by %s, diedSinceArrestAttempt is now false", actor.getCellRef().getRefId().c_str()); + mwmp::Main::get().getLocalPlayer()->diedSinceArrestAttempt = false; + /* + End of tes3mp addition + */ + return true; } diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index cef392ff1..3cd057830 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -61,6 +61,8 @@ LocalPlayer::LocalPlayer() jailProgressText = ""; jailEndText = ""; + + diedSinceArrestAttempt = false; } LocalPlayer::~LocalPlayer() diff --git a/apps/openmw/mwmp/processors/player/ProcessorPlayerResurrect.hpp b/apps/openmw/mwmp/processors/player/ProcessorPlayerResurrect.hpp index e0c7e39d0..c6e6ab5b3 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorPlayerResurrect.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorPlayerResurrect.hpp @@ -52,6 +52,12 @@ namespace mwmp // readied but be unable to use it unless we clear it here playerPtr.getClass().getNpcStats(playerPtr).setDrawState(MWMechanics::DrawState_Nothing); + // Record that the player has died since the last attempt was made to arrest them, + // used to make guards lenient enough to attempt an arrest again + player->diedSinceArrestAttempt = true; + + LOG_APPEND(Log::LOG_INFO, "- diedSinceArrestAttempt is now true"); + packet.setPlayer(player); packet.Send(serverAddr); diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index 1f971d285..0b3a2cc9a 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -263,6 +263,8 @@ namespace mwmp std::string jailEndText; unsigned int resurrectType; + + bool diedSinceArrestAttempt; }; } From 8c9d6a01608e8b69425c337208b2968419e263d6 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 4 Sep 2017 15:44:10 +0300 Subject: [PATCH 23/44] [Client] Ensure that LocalPlayer's isWerewolf starts out false --- apps/openmw/mwmp/LocalPlayer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 3cd057830..b49f4e554 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -62,6 +62,8 @@ LocalPlayer::LocalPlayer() jailProgressText = ""; jailEndText = ""; + isWerewolf = false; + diedSinceArrestAttempt = false; } From b94c0a999130c0045fb035dbf67e86f01e57afe6 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 4 Sep 2017 20:21:06 +0300 Subject: [PATCH 24/44] [Client] Don't send Attribute & Skill packets as werewolf, part 2 --- apps/openmw/mwmp/LocalPlayer.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index b49f4e554..16a3d4441 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -97,15 +97,8 @@ void LocalPlayer::update() updateDeadState(); updateEquipment(); updateStatsDynamic(); - - // Only send attributes and skills if we are not a werewolf, or they will be - // overwritten by the werewolf ones - if (!isWerewolf) - { - updateAttributes(); - updateSkills(); - } - + updateAttributes(); + updateSkills(); updateLevel(); updateBounty(); } @@ -234,6 +227,10 @@ void LocalPlayer::updateStatsDynamic(bool forceUpdate) void LocalPlayer::updateAttributes(bool forceUpdate) { + // Only send attributes if we are not a werewolf, or they will be + // overwritten by the werewolf ones + if (isWerewolf) return; + MWWorld::Ptr ptrPlayer = getPlayerPtr(); const MWMechanics::NpcStats &ptrNpcStats = ptrPlayer.getClass().getNpcStats(ptrPlayer); bool attributesChanged = false; @@ -256,6 +253,10 @@ void LocalPlayer::updateAttributes(bool forceUpdate) void LocalPlayer::updateSkills(bool forceUpdate) { + // Only send skills if we are not a werewolf, or they will be + // overwritten by the werewolf ones + if (isWerewolf) return; + MWWorld::Ptr ptrPlayer = getPlayerPtr(); const MWMechanics::NpcStats &ptrNpcStats = ptrPlayer.getClass().getNpcStats(ptrPlayer); From dca31b7ffa4fc4c8f2b15fcf0491f9e9ef4cde23 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 4 Sep 2017 19:34:26 +0000 Subject: [PATCH 25/44] Remove redundant _boundingBoxComputed which no longer exists in osg master (Fixes #4075) --- components/sceneutil/morphgeometry.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 2ffbace3b..1b7e4ca93 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -62,10 +62,7 @@ void MorphGeometry::dirty() { mDirty = true; if (!mMorphedBoundingBox) - { - _boundingBoxComputed = false; dirtyBound(); - } } osg::ref_ptr MorphGeometry::getSourceGeometry() const From 7559d2531773a256ef83a803938d8e9110c6693c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 6 Sep 2017 15:11:47 +0400 Subject: [PATCH 26/44] Update alchemy effects after every created potion (#4079) --- apps/openmw/mwmechanics/alchemy.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 124468641..48705dc72 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -262,22 +262,16 @@ const ESM::Potion *MWMechanics::Alchemy::getRecord(const ESM::Potion& toFind) co void MWMechanics::Alchemy::removeIngredients() { - bool needsUpdate = false; - for (TIngredientsContainer::iterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) if (!iter->isEmpty()) { iter->getContainerStore()->remove(*iter, 1, mAlchemist); if (iter->getRefData().getCount()<1) - { - needsUpdate = true; *iter = MWWorld::Ptr(); - } } - if (needsUpdate) - updateEffects(); + updateEffects(); } void MWMechanics::Alchemy::addPotion (const std::string& name) From 538498230b97f478532441c75e2afe125cee43c8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 6 Sep 2017 15:59:54 +0400 Subject: [PATCH 27/44] Declare mClient variable --- components/widgets/windowcaption.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/widgets/windowcaption.hpp b/components/widgets/windowcaption.hpp index bdd4c0a2e..b45da2d1c 100644 --- a/components/widgets/windowcaption.hpp +++ b/components/widgets/windowcaption.hpp @@ -23,6 +23,7 @@ namespace Gui private: MyGUI::Widget* mLeft; MyGUI::Widget* mRight; + MyGUI::Widget* mClient; void align(); }; From dc0313a36f7c01952c0f10f89566441bc05a8cac Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Sep 2017 21:06:10 +0400 Subject: [PATCH 28/44] Use base skill value when calculating rank requirements --- apps/openmw/mwmechanics/npcstats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 595635206..f0fc7fb6e 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -380,7 +380,7 @@ bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int for (int i=0; i<7; ++i) { if (faction.mData.mSkills[i] != -1) - skills.push_back (static_cast (getSkill (faction.mData.mSkills[i]).getModified())); + skills.push_back (static_cast (getSkill (faction.mData.mSkills[i]).getBase())); } if (skills.empty()) From ac2f20f983ca9be113e36d147e9fec9f226b0b91 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 8 Sep 2017 19:42:06 +0400 Subject: [PATCH 29/44] Update a disposition bar when a dialogue widget is disabled, but visible --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index f478dad7e..2e80301d2 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -634,7 +634,7 @@ namespace MWGui void DialogueWindow::onFrame() { - if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + if(mMainWidget->getVisible() && mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); mDispositionBar->setProgressRange(100); From 3c0ec0d6d02d9ccd882e283e5973876259c42bfc Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 17:26:46 +0100 Subject: [PATCH 30/44] If CMake supports it, sets the debugger working directory for Visual Studio --- apps/bsatool/CMakeLists.txt | 6 ++++++ apps/esmtool/CMakeLists.txt | 6 ++++++ apps/essimporter/CMakeLists.txt | 6 ++++++ apps/launcher/CMakeLists.txt | 6 +++++- apps/mwiniimporter/CMakeLists.txt | 6 ++++++ apps/niftest/CMakeLists.txt | 6 ++++++ apps/opencs/CMakeLists.txt | 4 ++++ apps/openmw/CMakeLists.txt | 4 ++++ apps/openmw_test_suite/CMakeLists.txt | 6 ++++++ apps/wizard/CMakeLists.txt | 6 ++++++ 10 files changed, 55 insertions(+), 1 deletion(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 27baff815..19c9558cf 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -18,3 +18,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(bsatool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 1d5e662d8..b0c67d8fa 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -21,3 +21,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(esmtool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 93f53d0e8..a7c25ca2e 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -46,3 +46,9 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") endif(WIN32) + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-essimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 8cbe18d51..5d70aa917 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -110,4 +110,8 @@ if (BUILD_WITH_CODE_COVERAGE) target_link_libraries(openmw-launcher gcov) endif() - +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-launcher PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 4bd661685..071137556 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -33,3 +33,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-iniimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index d7f0200d2..efe440ae7 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -17,3 +17,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(niftest gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(niftest PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index fc8930b71..65c1d8ed8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -260,6 +260,10 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) + + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-cs PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 89b94ce12..3ef62dfa3 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -215,6 +215,10 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) + + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) if (WIN32) diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index ea4b1209c..7d6898367 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -24,6 +24,12 @@ if (GTEST_FOUND) if (UNIX AND NOT APPLE) target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT}) endif() + + if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw_test_suite PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) + endif (MSVC) endif() diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index d2b9ab0f6..2d9a11c51 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -143,3 +143,9 @@ endif() if (WIN32) INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".") endif(WIN32) + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-wizard PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file From 1e585ac71a4b6caea25bd6f24b02d70d165e3582 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 8 Sep 2017 22:50:07 +0200 Subject: [PATCH 31/44] Log a warning in case of missing bookart instead of showing a pink rectangle (Fixes #3826) --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/formatting.cpp | 18 +++++++++++++----- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d7ccfa3e4..4560ab270 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -360,7 +360,7 @@ namespace MWBase // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path) = 0; - virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0; + virtual std::string correctBookartPath(const std::string& path, int width, int height, bool* exists = nullptr) = 0; virtual std::string correctTexturePath(const std::string& path) = 0; virtual bool textureExists(const std::string& path) = 0; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 72e1c09f3..cf4a5b589 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -275,8 +275,6 @@ namespace MWGui { case BookTextParser::Event_ImgTag: { - pag.setIgnoreLeadingEmptyLines(false); - const BookTextParser::Attributes & attr = parser.getAttributes(); if (attr.find("src") == attr.end() || attr.find("width") == attr.end() || attr.find("height") == attr.end()) @@ -286,8 +284,19 @@ namespace MWGui int width = MyGUI::utility::parseInt(attr.at("width")); int height = MyGUI::utility::parseInt(attr.at("height")); + bool exists; + std::string correctedSrc = MWBase::Environment::get().getWindowManager()->correctBookartPath(src, width, height, &exists); + + if (!exists) + { + std::cerr << "Warning: Could not find \"" << src << "\" referenced by an tag." << std::endl; + break; + } + + pag.setIgnoreLeadingEmptyLines(false); + ImageElement elem(paper, pag, mBlockStyle, - src, width, height); + correctedSrc, width, height); elem.paginate(); break; } @@ -471,8 +480,7 @@ namespace MWGui MyGUI::IntCoord(left, pag.getCurrentTop(), width, mImageHeight), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - std::string image = MWBase::Environment::get().getWindowManager()->correctBookartPath(src, width, mImageHeight); - mImageBox->setImageTexture(image); + mImageBox->setImageTexture(src); mImageBox->setProperty("NeedMouse", "false"); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 33ba58cc7..4b7b3c387 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2090,9 +2090,12 @@ namespace MWGui return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); } - std::string WindowManager::correctBookartPath(const std::string& path, int width, int height) + std::string WindowManager::correctBookartPath(const std::string& path, int width, int height, bool* exists) { - return Misc::ResourceHelpers::correctBookartPath(path, width, height, mResourceSystem->getVFS()); + std::string corrected = Misc::ResourceHelpers::correctBookartPath(path, width, height, mResourceSystem->getVFS()); + if (exists) + *exists = mResourceSystem->getVFS()->exists(corrected); + return corrected; } std::string WindowManager::correctTexturePath(const std::string& path) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ceb6f62b7..4f06afb7d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -388,7 +388,7 @@ namespace MWGui // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path); - virtual std::string correctBookartPath(const std::string& path, int width, int height); + virtual std::string correctBookartPath(const std::string& path, int width, int height, bool* exists = nullptr); virtual std::string correctTexturePath(const std::string& path); virtual bool textureExists(const std::string& path); From 5ce34f1cbfe0527a3e4b03a6b459b7a52324e067 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 22:17:42 +0100 Subject: [PATCH 32/44] Move new behaviour into macro to reduce code duplication --- apps/bsatool/CMakeLists.txt | 10 ++-------- apps/esmtool/CMakeLists.txt | 10 ++-------- apps/essimporter/CMakeLists.txt | 10 ++-------- apps/launcher/CMakeLists.txt | 10 ++-------- apps/mwiniimporter/CMakeLists.txt | 10 ++-------- apps/niftest/CMakeLists.txt | 10 ++-------- apps/opencs/CMakeLists.txt | 6 +----- apps/openmw/CMakeLists.txt | 6 +----- apps/openmw_test_suite/CMakeLists.txt | 8 +------- apps/wizard/CMakeLists.txt | 8 +------- cmake/OpenMWMacros.cmake | 9 +++++++++ 11 files changed, 25 insertions(+), 72 deletions(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 19c9558cf..167ab9d2c 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -4,7 +4,7 @@ set(BSATOOL source_group(apps\\bsatool FILES ${BSATOOL}) # Main executable -add_executable(bsatool +openmw_add_executable(bsatool ${BSATOOL} ) @@ -17,10 +17,4 @@ target_link_libraries(bsatool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(bsatool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index b0c67d8fa..90964f2d7 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -8,7 +8,7 @@ set(ESMTOOL source_group(apps\\esmtool FILES ${ESMTOOL}) # Main executable -add_executable(esmtool +openmw_add_executable(esmtool ${ESMTOOL} ) @@ -20,10 +20,4 @@ target_link_libraries(esmtool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(esmtool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index a7c25ca2e..69200583e 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -28,7 +28,7 @@ set(ESSIMPORTER_FILES convertplayer.cpp ) -add_executable(openmw-essimporter +openmw_add_executable(openmw-essimporter ${ESSIMPORTER_FILES} ) @@ -45,10 +45,4 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") -endif(WIN32) - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-essimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif(WIN32) \ No newline at end of file diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 5d70aa917..70a6708a8 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -78,7 +78,7 @@ if(NOT WIN32) endif(NOT WIN32) # Main executable -add_executable(openmw-launcher +openmw_add_executable(openmw-launcher ${GUI_TYPE} ${LAUNCHER} ${LAUNCHER_HEADER} @@ -108,10 +108,4 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-launcher gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-launcher PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 071137556..f1717a4c3 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -9,7 +9,7 @@ set(MWINIIMPORT_HEADER source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER}) -add_executable(openmw-iniimporter +openmw_add_executable(openmw-iniimporter ${MWINIIMPORT} ) @@ -32,10 +32,4 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-iniimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index efe440ae7..10119d7d7 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -4,7 +4,7 @@ set(NIFTEST source_group(components\\nif\\tests FILES ${NIFTEST}) # Main executable -add_executable(niftest +openmw_add_executable(niftest ${NIFTEST} ) @@ -16,10 +16,4 @@ target_link_libraries(niftest if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(niftest gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(niftest PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 65c1d8ed8..281921c81 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -174,7 +174,7 @@ else() set (OPENCS_OPENMW_CFG "") endif(APPLE) -add_executable(openmw-cs +openmw_add_executable(openmw-cs MACOSX_BUNDLE ${OPENCS_SRC} ${OPENCS_UI_HDR} @@ -260,10 +260,6 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) - - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-cs PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3ef62dfa3..134953f3d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -99,7 +99,7 @@ add_openmw_dir (mwbase # Main executable if (NOT ANDROID) - add_executable(openmw + openmw_add_executable(openmw ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ${APPLE_BUNDLE_RESOURCES} @@ -215,10 +215,6 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) - - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) if (WIN32) diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 7d6898367..9b09bc41f 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -17,19 +17,13 @@ if (GTEST_FOUND) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) - add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) + openmw_add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) target_link_libraries(openmw_test_suite ${GTEST_BOTH_LIBRARIES} components) # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT}) endif() - - if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw_test_suite PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) - endif (MSVC) endif() diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 2d9a11c51..5f7338e52 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -96,7 +96,7 @@ if (OPENMW_USE_UNSHIELD) include_directories(${LIBUNSHIELD_INCLUDE_DIRS}) endif() -add_executable(openmw-wizard +openmw_add_executable(openmw-wizard ${GUI_TYPE} ${WIZARD} ${WIZARD_HEADER} @@ -143,9 +143,3 @@ endif() if (WIN32) INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".") endif(WIN32) - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-wizard PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index c5669fa70..9a1722dab 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -142,3 +142,12 @@ foreach (u ${ARGN}) add_hdr (OPENCS ${dir} ${u}) endforeach (u) endmacro (opencs_hdrs_noqt) + +macro (openmw_add_executable target) + add_executable(${target} ${ARGN}) + if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) + endif (MSVC) +endmacro (openmw_add_executable) From 8c74f16247b1888f359ba79740e4cf97d9b8b5f7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 22:20:04 +0100 Subject: [PATCH 33/44] Restore trailing new lines to shrink PR --- apps/bsatool/CMakeLists.txt | 2 +- apps/esmtool/CMakeLists.txt | 2 +- apps/essimporter/CMakeLists.txt | 2 +- apps/launcher/CMakeLists.txt | 3 ++- apps/mwiniimporter/CMakeLists.txt | 2 +- apps/niftest/CMakeLists.txt | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 167ab9d2c..ec0615ff9 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -17,4 +17,4 @@ target_link_libraries(bsatool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) -endif() \ No newline at end of file +endif() diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 90964f2d7..122ca2f3a 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -20,4 +20,4 @@ target_link_libraries(esmtool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) -endif() \ No newline at end of file +endif() diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 69200583e..82182b7fa 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -45,4 +45,4 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") -endif(WIN32) \ No newline at end of file +endif(WIN32) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 70a6708a8..70281910f 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -108,4 +108,5 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-launcher gcov) -endif() \ No newline at end of file +endif() + diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index f1717a4c3..e83656708 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -32,4 +32,4 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) -endif() \ No newline at end of file +endif() diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index 10119d7d7..3cbee2b7e 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -16,4 +16,4 @@ target_link_libraries(niftest if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(niftest gcov) -endif() \ No newline at end of file +endif() From a9b95596bc55deba7daeec8249c811cd75cfa746 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 22:21:00 +0100 Subject: [PATCH 34/44] Add a missed trailing new line. --- apps/launcher/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 70281910f..aac076404 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -110,3 +110,4 @@ if (BUILD_WITH_CODE_COVERAGE) target_link_libraries(openmw-launcher gcov) endif() + From c9f099ce07eb0da9df1d84d15e0993f63a6ec33e Mon Sep 17 00:00:00 2001 From: krizd Date: Sat, 9 Sep 2017 03:06:03 +0100 Subject: [PATCH 35/44] Change CMake version check to include 3.8 --- cmake/OpenMWMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 9a1722dab..460751445 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -146,8 +146,8 @@ endmacro (opencs_hdrs_noqt) macro (openmw_add_executable target) add_executable(${target} ${ARGN}) if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) + if (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) + endif (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) endif (MSVC) endmacro (openmw_add_executable) From 33c77d7a2aefaad6219bba2c43fc76497ceb32e4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 9 Sep 2017 17:22:55 +0100 Subject: [PATCH 36/44] Try using cmake_parse_arguments to make the macro work --- cmake/OpenMWMacros.cmake | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 460751445..11f230ac6 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -143,8 +143,34 @@ add_hdr (OPENCS ${dir} ${u}) endforeach (u) endmacro (opencs_hdrs_noqt) +include(CMakeParseArguments) + macro (openmw_add_executable target) - add_executable(${target} ${ARGN}) + set(OMW_ADD_EXE_OPTIONS WIN32 MACOSX_BUNDLE EXCLUDE_FROM_ALL) + set(OMW_ADD_EXE_VALUES) + set(OMW_ADD_EXE_MULTI_VALUES) + cmake_parse_arguments(OMW_ADD_EXE "${OMW_ADD_EXE_OPTIONS}" "${OMW_ADD_EXE_VALUES}" "${OMW_ADD_EXE_MULTI_VALUES}" ${ARGN}) + + if (OMW_ADD_EXE_WIN32) + set(OMW_ADD_EXE_WIN32_VALUE WIN32) + endif (OMW_ADD_EXE_WIN32) + + if (OMW_ADD_EXE_MACOSX_BUNDLE) + set(OMW_ADD_EXE_MACOSX_BUNDLE_VALUE MACOSX_BUNDLE) + endif (OMW_ADD_EXE_MACOSX_BUNDLE) + + if (OMW_ADD_EXE_EXCLUDE_FROM_ALL) + set(OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE EXCLUDE_FROM_ALL) + endif (OMW_ADD_EXE_EXCLUDE_FROM_ALL) + + message("Target: " ${target}) + message("WIN32: ${OMW_ADD_EXE_WIN32_VALUE}") + message("MACOSX_BUNDLE: ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE}") + message("EXCLUDE_FROM_ALL: ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE}") + message("Unparsed: ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + + add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} "${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + if (MSVC) if (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") From 9503d6186640a3c578e424c98ccf65f5c8ca3a76 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 9 Sep 2017 23:22:16 +0300 Subject: [PATCH 37/44] Use const nodeMap in creature animation --- apps/openmw/mwrender/creatureanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 2ad362b33..735c0b66d 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -118,7 +118,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item)); const NodeMap& nodeMap = getNodeMap(); - NodeMap::const_iterator found = getNodeMap().find(Misc::StringUtils::lowerCase(bonename)); + NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(bonename)); if (found == nodeMap.end()) throw std::runtime_error("Can't find attachment node " + bonename); osg::ref_ptr attached = SceneUtil::attach(node, mObjectRoot, bonename, found->second.get()); From de14e436803ac3ddb8ad9836d7ce5d90e9a13b68 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 10 Sep 2017 03:18:22 +0100 Subject: [PATCH 38/44] Seemingly fix everything by setting policies that were unset upon entering the macro --- cmake/OpenMWMacros.cmake | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 11f230ac6..6686ea131 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -163,13 +163,11 @@ macro (openmw_add_executable target) set(OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE EXCLUDE_FROM_ALL) endif (OMW_ADD_EXE_EXCLUDE_FROM_ALL) - message("Target: " ${target}) - message("WIN32: ${OMW_ADD_EXE_WIN32_VALUE}") - message("MACOSX_BUNDLE: ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE}") - message("EXCLUDE_FROM_ALL: ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE}") - message("Unparsed: ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + # AnyOldName3 says: I have no idea why or if it's even supposed to happen, but somehow entering this macro confuses CMake about which policies should be set. They are restored here. + cmake_policy(SET CMP0003 NEW) + cmake_policy(SET CMP0020 NEW) - add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} "${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}) if (MSVC) if (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) From 661232222f428598e5659f8a277a426434318551 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Sep 2017 15:26:48 +0400 Subject: [PATCH 39/44] Allow guards to attack fighting creatures only in fAlarmRadius range --- apps/openmw/mwmechanics/actors.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ed510e616..d15e1a1a5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -394,10 +394,15 @@ namespace MWMechanics aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); } } - + // Make guards go aggressive with creatures that are in combat, unless the creature is a follower or escorter if (actor1.getClass().isClass(actor1, "Guard") && !actor2.getClass().isNpc()) { + // Check if the creature is too far + static const float fAlarmRadius = MWBase::Environment::get().getWorld()->getStore().get().find("fAlarmRadius")->getFloat(); + if (sqrDist > fAlarmRadius * fAlarmRadius) + return; + bool followerOrEscorter = false; for (std::list::const_iterator it = creatureStats2.getAiSequence().begin(); it != creatureStats2.getAiSequence().end(); ++it) { From afbdc27a34995e0bcef7386c4229cdedc3777f0c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 10 Sep 2017 18:30:10 +0100 Subject: [PATCH 40/44] Move calls to cmake_minimum_required as early in the CMake process as possible. --- CMakeLists.txt | 71 +++++++++++++++++++++------------------- cmake/OpenMWMacros.cmake | 4 --- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a78eac572..0050104cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,40 @@ +# Apps and tools +option(BUILD_OPENMW "build OpenMW" ON) +option(BUILD_BSATOOL "build BSA extractor" ON) +option(BUILD_ESMTOOL "build ESM inspector" ON) +option(BUILD_LAUNCHER "build Launcher" ON) +option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) +option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON) +option(BUILD_OPENCS "build OpenMW Construction Set" ON) +option(BUILD_WIZARD "build Installation Wizard" ON) +option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) +option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) +option(BUILD_NIFTEST "build nif file tester" OFF) +option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) +option(BUILD_DOCS "build documentation." OFF ) + +if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) + set(USE_QT FALSE) +else() + set(USE_QT TRUE) +endif() + +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) +endif() + +if (APPLE) + # OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db + cmake_minimum_required(VERSION 3.1.0) +elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5) + # 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows. + cmake_minimum_required(VERSION 2.8.11) +else() + # We probably support older versions than this. + cmake_minimum_required(VERSION 2.6) +endif() + project(OpenMW) # If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. @@ -59,21 +96,6 @@ option(QT_STATIC "Link static build of QT into the binaries" FALSE) option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) -# Apps and tools -option(BUILD_OPENMW "build OpenMW" ON) -option(BUILD_BSATOOL "build BSA extractor" ON) -option(BUILD_ESMTOOL "build ESM inspector" ON) -option(BUILD_LAUNCHER "build Launcher" ON) -option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) -option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON) -option(BUILD_OPENCS "build OpenMW Construction Set" ON) -option(BUILD_WIZARD "build Installation Wizard" ON) -option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) -option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) -option(BUILD_NIFTEST "build nif file tester" OFF) -option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) -option(BUILD_DOCS "build documentation." OFF ) - # what is necessary to build documentation IF( BUILD_DOCS ) # Builds the documentation. @@ -120,16 +142,8 @@ if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) endif() -if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) - set(USE_QT FALSE) -else() - set(USE_QT TRUE) -endif() - # Dependencies if (USE_QT) - set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") - set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) message(STATUS "Using Qt${DESIRED_QT_VERSION}") if (DESIRED_QT_VERSION MATCHES 4) @@ -144,17 +158,6 @@ if (USE_QT) endif() endif() -if (APPLE) - # OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db - cmake_minimum_required(VERSION 3.1.0) -elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5) - # 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows. - cmake_minimum_required(VERSION 2.8.11) -else() - # We probably support older versions than this. - cmake_minimum_required(VERSION 2.6) -endif() - # Sound setup find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE) # Required for building the FFmpeg headers diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 6686ea131..6573265bd 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -163,10 +163,6 @@ macro (openmw_add_executable target) set(OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE EXCLUDE_FROM_ALL) endif (OMW_ADD_EXE_EXCLUDE_FROM_ALL) - # AnyOldName3 says: I have no idea why or if it's even supposed to happen, but somehow entering this macro confuses CMake about which policies should be set. They are restored here. - cmake_policy(SET CMP0003 NEW) - cmake_policy(SET CMP0020 NEW) - add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}) if (MSVC) From 97ff24b8d6ffcbbb80b52725358ed8a683712c28 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 10 Sep 2017 20:48:09 +0300 Subject: [PATCH 41/44] Change ctl to ctrl in OpenMW-CS shortcut manager --- apps/opencs/model/prefs/shortcutmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 6ae778fff..c4b46958d 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -132,7 +132,7 @@ namespace CSMPrefs if (mods && i == 0) { if (mods & Qt::ControlModifier) - result.append("Ctl+"); + result.append("Ctrl+"); if (mods & Qt::ShiftModifier) result.append("Shift+"); if (mods & Qt::AltModifier) @@ -196,7 +196,7 @@ namespace CSMPrefs std::string name = value.substr(start, end - start); - if (name == "Ctl") + if (name == "Ctrl") { mods |= Qt::ControlModifier; } From c6fd75bf42cd3a167282107329e79bef5053d51a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Sep 2017 14:21:05 +0400 Subject: [PATCH 42/44] Take in account elemental shields for GetResist and SetResist script commands (bug #4093) --- apps/openmw/mwscript/statsextensions.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 6b1953917..70910ec2f 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1189,6 +1189,14 @@ namespace MWScript if (mNegativeEffect != -1) currentValue -= effects.get(mNegativeEffect).getMagnitude(); + // GetResist* should take in account elemental shields + if (mPositiveEffect == ESM::MagicEffect::ResistFire) + currentValue += effects.get(ESM::MagicEffect::FireShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistShock) + currentValue += effects.get(ESM::MagicEffect::LightningShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistFrost) + currentValue += effects.get(ESM::MagicEffect::FrostShield).getMagnitude(); + int ret = static_cast(currentValue); runtime.push(ret); } @@ -1215,6 +1223,14 @@ namespace MWScript if (mNegativeEffect != -1) currentValue -= effects.get(mNegativeEffect).getMagnitude(); + // SetResist* should take in account elemental shields + if (mPositiveEffect == ESM::MagicEffect::ResistFire) + currentValue += effects.get(ESM::MagicEffect::FireShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistShock) + currentValue += effects.get(ESM::MagicEffect::LightningShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistFrost) + currentValue += effects.get(ESM::MagicEffect::FrostShield).getMagnitude(); + int arg = runtime[0].mInteger; runtime.pop(); effects.modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); From 7760e4514c767e266bd72697567f4b9868653ed8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Sep 2017 22:47:34 +0400 Subject: [PATCH 43/44] Allow to add levelup a description for levels > 20 --- apps/openmw/mwgui/levelupdialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 362ad3b1c..da8e93279 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -143,10 +143,10 @@ namespace MWGui mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + MyGUI::utility::toString(level)); std::string levelupdescription; - if(level > 20) + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+MyGUI::utility::toString(level)); + + if (levelupdescription == "") levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default"); - else - levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+MyGUI::utility::toString(level)); mLevelDescription->setCaption (levelupdescription); From 5904e5a267741c230cee1b2bb258693ed7781d48 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Sep 2017 10:47:35 +0200 Subject: [PATCH 44/44] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index bb773c4ef..d9782ccf3 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -34,6 +34,7 @@ Programmers Ben Shealy (bentsherman) Bret Curtis (psi29a) Britt Mathis (galdor557) + Capostrophic cc9cii Chris Boyce (slothlife) Chris Robinson (KittyCat)