From 3194520dcd5eecb04540af0fc936bd303b38c566 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 30 Dec 2020 22:11:32 +0200 Subject: [PATCH 01/40] Move base_anim settings to settings-default.cfg --- apps/openmw/mwclass/npc.cpp | 12 ++++++------ apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 6 +++--- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- apps/openmw/mwrender/renderingmanager.cpp | 15 +++++++++------ components/resource/scenemanager.cpp | 2 ++ components/sceneutil/actorutil.cpp | 18 ++++++++++-------- files/settings-default.cfg | 16 ++++++++++++++++ 8 files changed, 49 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 27c98bbce..1f7e77daf 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -418,10 +418,10 @@ namespace MWClass { const MWWorld::LiveCellRef *ref = ptr.get(); - std::string model = "meshes\\base_anim.nif"; + std::string model = Settings::Manager::getString("xbaseanim", "Models"); const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); if(race->mData.mFlags & ESM::Race::Beast) - model = "meshes\\base_animkna.nif"; + model = Settings::Manager::getString("baseanimkna", "Models"); return model; } @@ -431,12 +431,12 @@ namespace MWClass const MWWorld::LiveCellRef *npc = ptr.get(); const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().search(npc->mBase->mRace); if(race && race->mData.mFlags & ESM::Race::Beast) - models.emplace_back("meshes\\base_animkna.nif"); + models.emplace_back(Settings::Manager::getString("baseanimkna", "Models")); // keep these always loaded just in case - models.emplace_back("meshes/xargonian_swimkna.nif"); - models.emplace_back("meshes/xbase_anim_female.nif"); - models.emplace_back("meshes/xbase_anim.nif"); + models.emplace_back(Settings::Manager::getString("xargonianswimkna", "Models")); + models.emplace_back(Settings::Manager::getString("xbaseanimfemale", "Models")); + models.emplace_back(Settings::Manager::getString("xbaseanim", "Models")); if (!npc->mBase->mModel.empty()) models.push_back("meshes/"+npc->mBase->mModel); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f8ff3780d..d8c759935 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1500,7 +1500,7 @@ namespace MWRender MWWorld::LiveCellRef *ref = mPtr.get(); if(ref->mBase->mFlags & ESM::Creature::Bipedal) { - defaultSkeleton = "meshes\\xbase_anim.nif"; + defaultSkeleton = Settings::Manager::getString("xbaseanim", "Models"); inject = true; } } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index f1df6c90f..298711162 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -10,7 +10,7 @@ #include #include #include - +#include #include #include "../mwbase/environment.hpp" @@ -35,7 +35,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, setObjectRoot(model, false, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\xbase_anim.nif", model); + addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model); addAnimSource(model, model); } } @@ -54,7 +54,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const if((ref->mBase->mFlags&ESM::Creature::Bipedal)) { - addAnimSource("meshes\\xbase_anim.nif", model); + addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model); } addAnimSource(model, model); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d97e57115..b538f0b7b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -524,7 +524,7 @@ void NpcAnimation::updateNpcBase() if(!is1stPerson) { - const std::string base = "meshes\\xbase_anim.nif"; + const std::string base = Settings::Manager::getString("xbaseanim", "Models"); if (smodel != base && !isWerewolf) addAnimSource(base, smodel); @@ -538,7 +538,7 @@ void NpcAnimation::updateNpcBase() } else { - const std::string base = "meshes\\xbase_anim.1st.nif"; + const std::string base = Settings::Manager::getString("xbaseanim1st", "Models"); if (smodel != base && !isWerewolf) addAnimSource(base, smodel); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6ba4baec5..a3aee5c0f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -456,12 +456,15 @@ namespace MWRender mSky->listAssetsToPreload(workItem->mModels, workItem->mTextures); mWater->listAssetsToPreload(workItem->mTextures); - const char* basemodels[] = {"xbase_anim", "xbase_anim.1st", "xbase_anim_female", "xbase_animkna"}; - for (size_t i=0; imModels.push_back(std::string("meshes/") + basemodels[i] + ".nif"); - workItem->mKeyframes.push_back(std::string("meshes/") + basemodels[i] + ".kf"); - } + workItem->mModels.push_back(Settings::Manager::getString("xbaseanim", "Models")); + workItem->mModels.push_back(Settings::Manager::getString("xbaseanim1st", "Models")); + workItem->mModels.push_back(Settings::Manager::getString("xbaseanimfemale", "Models")); + workItem->mModels.push_back(Settings::Manager::getString("xargonianswimkna", "Models")); + + workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanimkf", "Models")); + workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanim1stkf", "Models")); + workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanimfemalekf", "Models")); + workItem->mKeyframes.push_back(Settings::Manager::getString("xargonianswimknakf", "Models")); workItem->mTextures.emplace_back("textures/_land_default.dds"); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 71f11e382..92de2e0dd 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include #include diff --git a/components/sceneutil/actorutil.cpp b/components/sceneutil/actorutil.cpp index 988a61f60..a0785e413 100644 --- a/components/sceneutil/actorutil.cpp +++ b/components/sceneutil/actorutil.cpp @@ -1,5 +1,7 @@ #include "actorutil.hpp" +#include + namespace SceneUtil { std::string getActorSkeleton(bool firstPerson, bool isFemale, bool isBeast, bool isWerewolf) @@ -7,24 +9,24 @@ namespace SceneUtil if (!firstPerson) { if (isWerewolf) - return "meshes\\wolf\\skin.nif"; + return Settings::Manager::getString("wolfskin", "Models"); else if (isBeast) - return "meshes\\base_animkna.nif"; + return Settings::Manager::getString("baseanimkna", "Models"); else if (isFemale) - return "meshes\\base_anim_female.nif"; + return Settings::Manager::getString("baseanimfemale", "Models"); else - return "meshes\\base_anim.nif"; + return Settings::Manager::getString("baseanim", "Models"); } else { if (isWerewolf) - return "meshes\\wolf\\skin.1st.nif"; + return Settings::Manager::getString("wolfskin1st", "Models"); else if (isBeast) - return "meshes\\base_animkna.1st.nif"; + return Settings::Manager::getString("baseanimkna1st", "Models"); else if (isFemale) - return "meshes\\base_anim_female.1st.nif"; + return Settings::Manager::getString("baseanimfemale1st", "Models"); else - return "meshes\\base_anim.1st.nif"; + return Settings::Manager::getString("xbaseanim1st", "Models"); } } } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3660f56f0..db947f8ed 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -969,3 +969,19 @@ distance = 1 # A minimum size of groundcover chunk in cells (0.125, 0.25, 0.5, 1.0) min chunk size = 0.5 + +xbaseanim = meshes\xbase_anim.nif +baseanim = meshes\base_anim.nif +xbaseanim1st = meshes\xbase_anim.1st.nif +baseanimkna = meshes\base_animkna.nif +baseanimkna1st = meshes\base_animkna.1st.nif +xbaseanimfemale = meshes/xbase_anim_female.nif +baseanimfemale = meshes/base_anim_female.nif +baseanimfemale1st = meshes\base_anim_female.1st.nif +wolfskin = meshes\wolf\skin.nif +wolfskin1st = meshes\wolf\skin.1st.nif +xargonianswimkna = meshes/xargonian_swimkna.nif +xbaseanimkf = meshes\xbase_anim.kf +xbaseanim1stkf = meshes\xbase_anim.1st.kf +xbaseanimfemalekf = meshes/xbase_anim_female.kf +xargonianswimknakf = meshes/xargonian_swimkna.kf From 83ee1cc582e355a78e836d674bb228ec47cd1c9e Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Fri, 1 Jan 2021 22:51:23 +0200 Subject: [PATCH 02/40] fix xbase to baseanim --- apps/openmw/mwclass/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1f7e77daf..5de4c197e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -418,7 +418,7 @@ namespace MWClass { const MWWorld::LiveCellRef *ref = ptr.get(); - std::string model = Settings::Manager::getString("xbaseanim", "Models"); + std::string model = Settings::Manager::getString("baseanim", "Models"); const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); if(race->mData.mFlags & ESM::Race::Beast) model = Settings::Manager::getString("baseanimkna", "Models"); From f87c45c92a6cfba68d431398a1ceab57976b74ff Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 30 Jan 2021 16:03:02 +0200 Subject: [PATCH 03/40] Get collision box extents and center from btBvhTriangleMeshShape --- components/resource/bulletshapemanager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index bcadf51c4..d1da9090d 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -86,7 +86,17 @@ public: return osg::ref_ptr(); osg::ref_ptr shape (new BulletShape); - shape->mCollisionShape = new TriangleMeshShape(mTriangleMesh.release(), true); + btBvhTriangleMeshShape* triangleMeshShape = new TriangleMeshShape(mTriangleMesh.release(), true); + btVector3 aabbMin = triangleMeshShape->getLocalAabbMin(); + btVector3 aabbMax = triangleMeshShape->getLocalAabbMax(); + shape->mCollisionBox.extents[0] = (aabbMax[0] - aabbMin[0]) / 2.0f; + shape->mCollisionBox.extents[1] = (aabbMax[1] - aabbMin[1]) / 2.0f; + shape->mCollisionBox.extents[2] = (aabbMax[2] - aabbMin[2]) / 2.0f; + shape->mCollisionBox.center = osg::Vec3f( (aabbMax[0] + aabbMin[0]) / 2.0f, + (aabbMax[1] + aabbMin[1]) / 2.0f, + (aabbMax[2] + aabbMin[2]) / 2.0f ); + shape->mCollisionShape = triangleMeshShape; + return shape; } From 7edaa50195baad8ac126ca116b12049d0fe29e5d Mon Sep 17 00:00:00 2001 From: madsbuvi Date: Sun, 31 Jan 2021 18:02:05 +0100 Subject: [PATCH 04/40] another approach --- components/sceneutil/mwshadowtechnique.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 294780cfd..7476bc219 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -997,9 +997,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) } // 1. Traverse main scene graph - cv.pushStateSet( _shadowRecievingPlaceholderStateSet.get() ); - - osg::ref_ptr decoratorStateGraph = cv.getCurrentStateGraph(); + auto* shadowReceiverStateSet = vdd->getStateSet(cv.getTraversalNumber()); + shadowReceiverStateSet->clear(); + cv.pushStateSet(shadowReceiverStateSet); cullShadowReceivingScene(&cv); @@ -1426,7 +1426,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (numValidShadows>0) { - decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd, cv.getTraversalNumber())); + selectStateSetForRenderingShadow(*vdd, cv.getTraversalNumber()); } // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< Date: Mon, 1 Feb 2021 18:34:10 +0000 Subject: [PATCH 05/40] Fix the regression involving Cure --- apps/openmw/mwmechanics/actors.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c9fcf8280..cb3570d21 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -958,22 +958,22 @@ namespace MWMechanics if (actor.getClass().hasInventoryStore(actor)) actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Paralyze); } - else if (effects.get(ESM::MagicEffect::CureCommonDisease).getModifier() > 0) + if (effects.get(ESM::MagicEffect::CureCommonDisease).getModifier() > 0) { creatureStats.getSpells().purgeCommonDisease(); } - else if (effects.get(ESM::MagicEffect::CureBlightDisease).getModifier() > 0) + if (effects.get(ESM::MagicEffect::CureBlightDisease).getModifier() > 0) { creatureStats.getSpells().purgeBlightDisease(); } - else if (effects.get(ESM::MagicEffect::CureCorprusDisease).getModifier() > 0) + if (effects.get(ESM::MagicEffect::CureCorprusDisease).getModifier() > 0) { creatureStats.getActiveSpells().purgeCorprusDisease(); creatureStats.getSpells().purgeCorprusDisease(); if (actor.getClass().hasInventoryStore(actor)) actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Corprus, true); } - else if (effects.get(ESM::MagicEffect::RemoveCurse).getModifier() > 0) + if (effects.get(ESM::MagicEffect::RemoveCurse).getModifier() > 0) { creatureStats.getSpells().purgeCurses(); } From 7d3f2bc113aed491a004abab576e7871788eb400 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 2 Feb 2021 17:33:40 +0200 Subject: [PATCH 06/40] Convert underscores in bone names to whitespaces --- components/sceneutil/visitor.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 00d18ffcb..169e07ada 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -60,7 +60,19 @@ namespace SceneUtil void NodeMapVisitor::apply(osg::MatrixTransform& trans) { // Take transformation for first found node in file - const std::string nodeName = Misc::StringUtils::lowerCase(trans.getName()); + std::string originalNodeName = Misc::StringUtils::lowerCase(trans.getName()); + + // Convert underscores to whitespaces as a workaround for Collada (OpenMW's animation system uses whitespace-separated names) + std::string underscore = "_"; + std::size_t foundUnderscore = originalNodeName.find(underscore); + + if (foundUnderscore != std::string::npos) + { + std::replace(originalNodeName.begin(), originalNodeName.end(), '_', ' '); + //originalNodeName.replace(foundUnderscore.begin(), foundPageNumberEnd - foundPageNumber - 6, " ") ); + } + const std::string nodeName = originalNodeName; + mMap.emplace(nodeName, &trans); traverse(trans); From 2162b97fefd91678154d9a8b1c13723e64c266ab Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 2 Feb 2021 17:34:02 +0200 Subject: [PATCH 07/40] Handle case in osgAnimation bone names --- components/resource/keyframemanager.cpp | 3 ++- components/sceneutil/osgacontroller.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index d739392e8..b6417597d 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "animation.hpp" #include "objectcache.hpp" @@ -21,7 +22,7 @@ namespace Resource void RetrieveAnimationsVisitor::apply(osg::Node& node) { - if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && node.getName() == std::string("bip01")) + if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && Misc::StringUtils::lowerCase(node.getName()) == std::string("bip01")) { osg::ref_ptr callback = new SceneUtil::OsgAnimationController(); diff --git a/components/sceneutil/osgacontroller.cpp b/components/sceneutil/osgacontroller.cpp index 37aa525af..8f447621f 100644 --- a/components/sceneutil/osgacontroller.cpp +++ b/components/sceneutil/osgacontroller.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -83,7 +84,7 @@ namespace SceneUtil { osgAnimation::UpdateMatrixTransform* umt = dynamic_cast(cb); if (umt) - if (node.getName() != "bip01") link(umt); + if (Misc::StringUtils::lowerCase(node.getName()) != "bip01") link(umt); cb = cb->getNestedCallback(); } From 5b88d16a50bc3c5def4aa2bcb22501e7a0d2b0a0 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 2 Feb 2021 21:09:50 +0200 Subject: [PATCH 08/40] Clean-up --- components/resource/scenemanager.cpp | 2 -- components/sceneutil/visitor.cpp | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 92de2e0dd..71f11e382 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -26,8 +26,6 @@ #include #include -#include - #include #include diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 169e07ada..e632e7ce9 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -67,10 +67,8 @@ namespace SceneUtil std::size_t foundUnderscore = originalNodeName.find(underscore); if (foundUnderscore != std::string::npos) - { std::replace(originalNodeName.begin(), originalNodeName.end(), '_', ' '); - //originalNodeName.replace(foundUnderscore.begin(), foundPageNumberEnd - foundPageNumber - 6, " ") ); - } + const std::string nodeName = originalNodeName; mMap.emplace(nodeName, &trans); From 2c67f34c6d8ca8ba794e3b7bd810e7fdc07e8773 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 2 Feb 2021 21:18:14 +0200 Subject: [PATCH 09/40] Update base_anim file settings --- files/settings-default.cfg | 59 ++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index db947f8ed..8e365690d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -955,33 +955,62 @@ defer aabb update = true # Loading arbitrary meshes is not advised and may cause instability. load unsupported nif files = false -[Groundcover] - -# enable separate groundcover handling -enabled = false - -# A groundcover density (0.0 <= value <= 1.0) -# 1.0 means 100% density -density = 1.0 - -# A maximum distance in cells on which groundcover is rendered. -distance = 1 - -# A minimum size of groundcover chunk in cells (0.125, 0.25, 0.5, 1.0) -min chunk size = 0.5 - +# 3rd person base animation model that looks also for the corresponding kf-file xbaseanim = meshes\xbase_anim.nif + +# 3rd person base model with textkeys-data baseanim = meshes\base_anim.nif + +# 1st person base animation model that looks also for corresponding kf-file xbaseanim1st = meshes\xbase_anim.1st.nif + +# 3rd person beast race base model with textkeys-data baseanimkna = meshes\base_animkna.nif + +# 1st person beast race base animation model baseanimkna1st = meshes\base_animkna.1st.nif + +# 3rd person female base animation model xbaseanimfemale = meshes/xbase_anim_female.nif + +# 3rd person female base model with textkeys-data baseanimfemale = meshes/base_anim_female.nif + +# 1st person female base model with textkeys-data baseanimfemale1st = meshes\base_anim_female.1st.nif + +# 3rd person werewolf skin wolfskin = meshes\wolf\skin.nif + +# 1st person werewolf skin wolfskin1st = meshes\wolf\skin.1st.nif + +# Argonian smimkna xargonianswimkna = meshes/xargonian_swimkna.nif + +# File to load xbaseanim 3rd person animations xbaseanimkf = meshes\xbase_anim.kf + +# File to load xbaseanim 3rd person animations xbaseanim1stkf = meshes\xbase_anim.1st.kf + +# File to load xbaseanim animations from xbaseanimfemalekf = meshes/xbase_anim_female.kf + +# File to load xargonianswimkna animations from xargonianswimknakf = meshes/xargonian_swimkna.kf + +[Groundcover] + +# enable separate groundcover handling +enabled = false + +# A groundcover density (0.0 <= value <= 1.0) +# 1.0 means 100% density +density = 1.0 + +# A maximum distance in cells on which groundcover is rendered. +distance = 1 + +# A minimum size of groundcover chunk in cells (0.125, 0.25, 0.5, 1.0) +min chunk size = 0.5 From 1221889cf7c099ae0b00e7752b24448a1deac9e0 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 2 Feb 2021 21:41:17 +0200 Subject: [PATCH 10/40] Limit conversion of underscores to nodes origating from osgAnimation library --- components/sceneutil/visitor.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index e632e7ce9..60f99b2fe 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -62,12 +62,15 @@ namespace SceneUtil // Take transformation for first found node in file std::string originalNodeName = Misc::StringUtils::lowerCase(trans.getName()); - // Convert underscores to whitespaces as a workaround for Collada (OpenMW's animation system uses whitespace-separated names) - std::string underscore = "_"; - std::size_t foundUnderscore = originalNodeName.find(underscore); + if (trans.libraryName() == std::string("osgAnimation")) + { + // Convert underscores to whitespaces as a workaround for Collada (OpenMW's animation system uses whitespace-separated names) + std::string underscore = "_"; + std::size_t foundUnderscore = originalNodeName.find(underscore); - if (foundUnderscore != std::string::npos) - std::replace(originalNodeName.begin(), originalNodeName.end(), '_', ' '); + if (foundUnderscore != std::string::npos) + std::replace(originalNodeName.begin(), originalNodeName.end(), '_', ' '); + } const std::string nodeName = originalNodeName; From 382324173b3587fcf46ca00ce47cf2b71e75d9ac Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 2 Feb 2021 21:42:25 +0200 Subject: [PATCH 11/40] \ to / --- files/settings-default.cfg | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 8e365690d..67d944d19 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -956,19 +956,19 @@ defer aabb update = true load unsupported nif files = false # 3rd person base animation model that looks also for the corresponding kf-file -xbaseanim = meshes\xbase_anim.nif +xbaseanim = meshes/xbase_anim.nif # 3rd person base model with textkeys-data -baseanim = meshes\base_anim.nif +baseanim = meshes/base_anim.nif # 1st person base animation model that looks also for corresponding kf-file -xbaseanim1st = meshes\xbase_anim.1st.nif +xbaseanim1st = meshes/xbase_anim.1st.nif # 3rd person beast race base model with textkeys-data -baseanimkna = meshes\base_animkna.nif +baseanimkna = meshes/base_animkna.nif # 1st person beast race base animation model -baseanimkna1st = meshes\base_animkna.1st.nif +baseanimkna1st = meshes/base_animkna.1st.nif # 3rd person female base animation model xbaseanimfemale = meshes/xbase_anim_female.nif @@ -977,22 +977,22 @@ xbaseanimfemale = meshes/xbase_anim_female.nif baseanimfemale = meshes/base_anim_female.nif # 1st person female base model with textkeys-data -baseanimfemale1st = meshes\base_anim_female.1st.nif +baseanimfemale1st = meshes/base_anim_female.1st.nif # 3rd person werewolf skin -wolfskin = meshes\wolf\skin.nif +wolfskin = meshes/wolf/skin.nif # 1st person werewolf skin -wolfskin1st = meshes\wolf\skin.1st.nif +wolfskin1st = meshes/wolf/skin.1st.nif # Argonian smimkna xargonianswimkna = meshes/xargonian_swimkna.nif # File to load xbaseanim 3rd person animations -xbaseanimkf = meshes\xbase_anim.kf +xbaseanimkf = meshes/xbase_anim.kf # File to load xbaseanim 3rd person animations -xbaseanim1stkf = meshes\xbase_anim.1st.kf +xbaseanim1stkf = meshes/xbase_anim.1st.kf # File to load xbaseanim animations from xbaseanimfemalekf = meshes/xbase_anim_female.kf From 6c0c28c2eb8d41ee26dd562f332ce72c6a2c76c3 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 30 Jan 2021 16:03:02 +0200 Subject: [PATCH 12/40] Get collision box extents and center from btBvhTriangleMeshShape --- components/resource/bulletshapemanager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index bcadf51c4..d1da9090d 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -86,7 +86,17 @@ public: return osg::ref_ptr(); osg::ref_ptr shape (new BulletShape); - shape->mCollisionShape = new TriangleMeshShape(mTriangleMesh.release(), true); + btBvhTriangleMeshShape* triangleMeshShape = new TriangleMeshShape(mTriangleMesh.release(), true); + btVector3 aabbMin = triangleMeshShape->getLocalAabbMin(); + btVector3 aabbMax = triangleMeshShape->getLocalAabbMax(); + shape->mCollisionBox.extents[0] = (aabbMax[0] - aabbMin[0]) / 2.0f; + shape->mCollisionBox.extents[1] = (aabbMax[1] - aabbMin[1]) / 2.0f; + shape->mCollisionBox.extents[2] = (aabbMax[2] - aabbMin[2]) / 2.0f; + shape->mCollisionBox.center = osg::Vec3f( (aabbMax[0] + aabbMin[0]) / 2.0f, + (aabbMax[1] + aabbMin[1]) / 2.0f, + (aabbMax[2] + aabbMin[2]) / 2.0f ); + shape->mCollisionShape = triangleMeshShape; + return shape; } From b28d8251aaa7fbf0e5ccab4fede1c34e1e62ad00 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 30 Jan 2021 15:27:47 +0200 Subject: [PATCH 13/40] Clone animation tracks --- components/sceneutil/osgacontroller.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/osgacontroller.cpp b/components/sceneutil/osgacontroller.cpp index 8f447621f..766d0cb79 100644 --- a/components/sceneutil/osgacontroller.cpp +++ b/components/sceneutil/osgacontroller.cpp @@ -103,10 +103,14 @@ namespace SceneUtil } OsgAnimationController::OsgAnimationController(const OsgAnimationController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop) - , mMergedAnimationTracks(copy.mMergedAnimationTracks) , mEmulatedAnimations(copy.mEmulatedAnimations) { mLinker = nullptr; + for (const auto& mergedAnimationTrack : copy.mMergedAnimationTracks) + { + Resource::Animation* copiedAnimationTrack = dynamic_cast(mergedAnimationTrack.get()->clone(copyop)); + mMergedAnimationTracks.emplace_back(copiedAnimationTrack); + } } osg::Vec3f OsgAnimationController::getTranslation(float time) const From bae27e81993813d7de75fe9eb466fa7c50a9a6ad Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 2 Feb 2021 18:00:14 +0200 Subject: [PATCH 14/40] dynamic_cast to static_cast --- components/sceneutil/osgacontroller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/osgacontroller.cpp b/components/sceneutil/osgacontroller.cpp index 766d0cb79..b2d819117 100644 --- a/components/sceneutil/osgacontroller.cpp +++ b/components/sceneutil/osgacontroller.cpp @@ -108,7 +108,7 @@ namespace SceneUtil mLinker = nullptr; for (const auto& mergedAnimationTrack : copy.mMergedAnimationTracks) { - Resource::Animation* copiedAnimationTrack = dynamic_cast(mergedAnimationTrack.get()->clone(copyop)); + Resource::Animation* copiedAnimationTrack = static_cast(mergedAnimationTrack.get()->clone(copyop)); mMergedAnimationTracks.emplace_back(copiedAnimationTrack); } } From 384112746c3e7c7999853afb77076c23be4e2de1 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 3 Feb 2021 14:25:09 +0200 Subject: [PATCH 15/40] Add option for custom collision node with non-nif files --- apps/openmw/mwworld/scene.cpp | 4 +-- components/resource/bulletshapemanager.cpp | 32 +++++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index fcf2c4b38..57da414dd 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -115,6 +115,8 @@ namespace std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS()); const auto rotation = makeNodeRotation(ptr, RotationOrder::direct); + if (!physics.getObject(ptr)) + ptr.getClass().insertObject (ptr, model, rotation, physics); if (!onlyPhysics) { bool useAnim = ptr.getClass().useAnim(); @@ -134,8 +136,6 @@ namespace // Restore effect particles MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr); } - if (!physics.getObject(ptr)) - ptr.getClass().insertObject (ptr, model, rotation, physics); } void addObject(const MWWorld::Ptr& ptr, const MWPhysics::PhysicsSystem& physics, DetourNavigator::Navigator& navigator) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index d1da9090d..aceb9bb35 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -8,6 +8,7 @@ #include +#include #include #include @@ -145,11 +146,34 @@ osg::ref_ptr BulletShapeManager::getShape(const std::string & osg::ref_ptr constNode (mSceneManager->getTemplate(normalized)); osg::ref_ptr node (const_cast(constNode.get())); // const-trickery required because there is no const version of NodeVisitor - NodeToShapeVisitor visitor; - node->accept(visitor); - shape = visitor.getShape(); + + // Check first if there's a custom collision node + SceneUtil::FindByNameVisitor nameFinder("Collision"); + node->accept(nameFinder); + if (nameFinder.mFoundNode) + { + NodeToShapeVisitor visitor; + nameFinder.mFoundNode->accept(visitor); + shape = visitor.getShape(); + for (unsigned int i = 0; i < nameFinder.mFoundNode->getNumParents(); ++i) + { + nameFinder.mFoundNode->getParent(i)->removeChild(nameFinder.mFoundNode); + } + + /* // CleanObjectRootVisitor is an alternative method + SceneUtil::CleanObjectRootVisitor cleanerVisitor; + nameFinder.mFoundNode->accept(cleanerVisitor);*/ + } + + // Generate a collision shape from the mesh if (!shape) - return osg::ref_ptr(); + { + NodeToShapeVisitor visitor; + node->accept(visitor); + shape = visitor.getShape(); + if (!shape) + return osg::ref_ptr(); + } } mCache->addEntryToObjectCache(normalized, shape); From 5c32460153497359ef3815c6b79e4437c3667480 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 3 Feb 2021 14:25:50 +0200 Subject: [PATCH 16/40] Add underscore-separated node-names to reserved-list --- components/resource/scenemanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 71f11e382..70320760f 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -390,7 +390,8 @@ namespace Resource { const char* reserved[] = {"Head", "Neck", "Chest", "Groin", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", "Shield Bone", "Right Forearm", "Left Forearm", "Right Upper Arm", "Left Upper Arm", "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", "Left Knee", "Right Upper Leg", "Left Upper Leg", "Right Clavicle", - "Left Clavicle", "Weapon Bone", "Tail", "Bip01", "Root Bone", "BoneOffset", "AttachLight", "Arrow", "Camera"}; + "Left Clavicle", "Weapon Bone", "Tail", "Bip01", "Root Bone", "BoneOffset", "AttachLight", "Arrow", "Camera", "Collision", "Right_Wrist", "Left_Wrist", + "Shield_Bone", "Right_Forearm", "Left_Forearm", "Right_Upper_Arm", "Left_Clavicle", "Weapon_Bone", "Root_Bone"}; reservedNames = std::vector(reserved, reserved + sizeof(reserved)/sizeof(reserved[0])); From 0639f8b7c6d5536f8a0ab03a058ab16bfb54c8bb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 3 Feb 2021 18:45:22 +0000 Subject: [PATCH 17/40] Make the dummy texture for the character preview shadow-friendly --- apps/openmw/mwrender/characterpreview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 14735050c..262b03229 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -184,6 +184,9 @@ namespace MWRender osg::ref_ptr dummyTexture = new osg::Texture2D(); dummyTexture->setInternalFormat(GL_RED); dummyTexture->setTextureSize(1, 1); + // This might clash with a shadow map, so make sure it doesn't cast shadows + dummyTexture->setShadowComparison(true); + dummyTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS); stateset->setTextureAttributeAndModes(7, dummyTexture, osg::StateAttribute::ON); stateset->setTextureAttribute(7, noBlendAlphaEnv, osg::StateAttribute::ON); stateset->addUniform(new osg::Uniform("noAlpha", true)); From e91d1a2b42aa3b28e5f86acc83201702c08cc2b7 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 3 Feb 2021 21:16:26 +0200 Subject: [PATCH 18/40] Fix earlier broken commit --- apps/openmw/mwworld/scene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 57da414dd..fcf2c4b38 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -115,8 +115,6 @@ namespace std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS()); const auto rotation = makeNodeRotation(ptr, RotationOrder::direct); - if (!physics.getObject(ptr)) - ptr.getClass().insertObject (ptr, model, rotation, physics); if (!onlyPhysics) { bool useAnim = ptr.getClass().useAnim(); @@ -136,6 +134,8 @@ namespace // Restore effect particles MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr); } + if (!physics.getObject(ptr)) + ptr.getClass().insertObject (ptr, model, rotation, physics); } void addObject(const MWWorld::Ptr& ptr, const MWPhysics::PhysicsSystem& physics, DetourNavigator::Navigator& navigator) From 45fde84f4ff005d476a05b628a27329ce01d976a Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 3 Feb 2021 21:16:54 +0200 Subject: [PATCH 19/40] Use nodemasks and visitors for detecting custom collision shapes --- components/resource/bulletshapemanager.cpp | 13 +++++-------- components/resource/scenemanager.cpp | 9 +++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index aceb9bb35..ad37eda0d 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -148,21 +148,18 @@ osg::ref_ptr BulletShapeManager::getShape(const std::string & osg::ref_ptr node (const_cast(constNode.get())); // const-trickery required because there is no const version of NodeVisitor // Check first if there's a custom collision node + unsigned int visitAllNodesMask = 0xffffffff; SceneUtil::FindByNameVisitor nameFinder("Collision"); + nameFinder.setTraversalMask(visitAllNodesMask); + nameFinder.setNodeMaskOverride(visitAllNodesMask); node->accept(nameFinder); if (nameFinder.mFoundNode) { NodeToShapeVisitor visitor; + visitor.setTraversalMask(visitAllNodesMask); + visitor.setNodeMaskOverride(visitAllNodesMask); nameFinder.mFoundNode->accept(visitor); shape = visitor.getShape(); - for (unsigned int i = 0; i < nameFinder.mFoundNode->getNumParents(); ++i) - { - nameFinder.mFoundNode->getParent(i)->removeChild(nameFinder.mFoundNode); - } - - /* // CleanObjectRootVisitor is an alternative method - SceneUtil::CleanObjectRootVisitor cleanerVisitor; - nameFinder.mFoundNode->accept(cleanerVisitor);*/ } // Generate a collision shape from the mesh diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 70320760f..19cc96433 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -373,6 +374,14 @@ namespace Resource errormsg << "Error loading " << normalizedFilename << ": " << result.message() << " code " << result.status() << std::endl; throw std::runtime_error(errormsg.str()); } + + // Recognize and hide collision node + unsigned int hiddenNodeMask = 0; + SceneUtil::FindByNameVisitor nameFinder("Collision"); + result.getNode()->accept(nameFinder); + if (nameFinder.mFoundNode) + nameFinder.mFoundNode->setNodeMask(hiddenNodeMask); + return result.getNode(); } } From 61e014a7657092bf8ea1e426665ea3934169c560 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Thu, 4 Feb 2021 21:25:38 +0100 Subject: [PATCH 20/40] Allow negative values for ai stats --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/stat.cpp | 4 +++- apps/openmw/mwmechanics/stat.hpp | 2 +- apps/openmw/mwscript/aiextensions.cpp | 6 ++---- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa74164d9..b5b66ee01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ Bug #5758: Paralyzed actors behavior is inconsistent with vanilla Bug #5762: Movement solver is insufficiently robust Bug #5821: NPCs from mods getting removed if mod order was changed + Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee Feature #390: 3rd person look "over the shoulder" Feature #1536: Show more information about level on menu Feature #2386: Distant Statics in the form of Object Paging diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 7f71cf9b1..c87de2ccb 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -18,8 +18,10 @@ namespace MWMechanics } template - T Stat::getModified() const + T Stat::getModified(bool capped) const { + if(!capped) + return mModified; return std::max(static_cast(0), mModified); } diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 5f49da48e..fb9dca922 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -28,7 +28,7 @@ namespace MWMechanics const T& getBase() const; - T getModified() const; + T getModified(bool capped = true) const; T getCurrentModified() const; T getModifier() const; T getCurrentModifier() const; diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 499c2f672..223ae3a15 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -241,7 +241,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push(ptr.getClass().getCreatureStats (ptr).getAiSetting (mIndex).getModified()); + runtime.push(ptr.getClass().getCreatureStats (ptr).getAiSetting (mIndex).getModified(false)); } }; template @@ -276,9 +276,7 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWMechanics::Stat stat = ptr.getClass().getCreatureStats(ptr).getAiSetting(mIndex); - stat.setModified(value, 0); - ptr.getClass().getCreatureStats(ptr).setAiSetting(mIndex, stat); + ptr.getClass().getCreatureStats(ptr).setAiSetting(mIndex, value); ptr.getClass().setBaseAISetting(ptr.getCellRef().getRefId(), mIndex, value); } }; From d5844b098295389c3b757a5a3c54f0627780d59b Mon Sep 17 00:00:00 2001 From: unelsson Date: Thu, 4 Feb 2021 23:14:21 +0200 Subject: [PATCH 21/40] Use accompanying txt file for textkeys in osgAnimation formats --- components/resource/keyframemanager.cpp | 68 ++++++++++++++++++++----- components/resource/keyframemanager.hpp | 10 +++- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index b6417597d..923ce4326 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -18,7 +18,9 @@ namespace Resource { - RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr animationManager) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target), mAnimationManager(animationManager) {} + RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr animationManager, + const std::string& normalized, const VFS::Manager* vfs) : + osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target), mAnimationManager(animationManager), mNormalized(normalized), mVFS(vfs) {} void RetrieveAnimationsVisitor::apply(osg::Node& node) { @@ -39,27 +41,19 @@ namespace Resource osg::ref_ptr mergedAnimationTrack = new Resource::Animation; std::string animationName = animation->getName(); - std::string start = animationName + std::string(": start"); - std::string stop = animationName + std::string(": stop"); + mergedAnimationTrack->setName(animationName); const osgAnimation::ChannelList& channels = animation->getChannels(); for (const auto& channel: channels) { mergedAnimationTrack->addChannel(channel.get()->clone()); // is ->clone needed? } - mergedAnimationTrack->setName(animation->getName()); + callback->addMergedAnimationTrack(mergedAnimationTrack); float startTime = animation->getStartTime(); float stopTime = startTime + animation->getDuration(); - // mTextKeys is a nif-thing, used by OpenMW's animation system - // Format is likely "AnimationName: [Keyword_optional] [Start OR Stop]" - // AnimationNames are keywords like idle2, idle3... AiPackages and various mechanics control which animations are played - // Keywords can be stuff like Loop, Equip, Unequip, Block, InventoryHandtoHand, InventoryWeaponOneHand, PickProbe, Slash, Thrust, Chop... even "Slash Small Follow" - mTarget.mTextKeys.emplace(startTime, std::move(start)); - mTarget.mTextKeys.emplace(stopTime, std::move(stop)); - SceneUtil::EmulatedAnimation emulatedAnimation; emulatedAnimation.mStartTime = startTime; emulatedAnimation.mStopTime = stopTime; @@ -67,12 +61,62 @@ namespace Resource emulatedAnimations.emplace_back(emulatedAnimation); } } + + // mTextKeys is a nif-thing, used by OpenMW's animation system + // Format is likely "AnimationName: [Keyword_optional] [Start OR Stop]" + // AnimationNames are keywords like idle2, idle3... AiPackages and various mechanics control which animations are played + // Keywords can be stuff like Loop, Equip, Unequip, Block, InventoryHandtoHand, InventoryWeaponOneHand, PickProbe, Slash, Thrust, Chop... even "Slash Small Follow" + // osgAnimation formats should have a .txt file with the same name, each line holding a textkey and whitespace separated time value + // e.g. idle: start 0.0333 + try + { + Files::IStreamPtr textKeysFile = mVFS->get(changeFileExtension(mNormalized, "txt")); + std::string line; + while ( getline (*textKeysFile, line) ) + { + Log(Debug::Warning) << "add textkey ***" << parseTextKey(line) << "***" << parseTimeSignature(line) << "***"; + mTarget.mTextKeys.emplace(parseTimeSignature(line), std::move(parseTextKey(line))); + } + } + catch (std::exception& e) + { + Log(Debug::Warning) << "No textkey file found for " << mNormalized; + } + callback->setEmulatedAnimations(emulatedAnimations); mTarget.mKeyframeControllers.emplace(node.getName(), callback); } traverse(node); } + + std::string RetrieveAnimationsVisitor::parseTextKey(const std::string& line) + { + size_t spacePos = line.find_last_of(' '); + if (spacePos != std::string::npos) + return line.substr(0, spacePos); + return ""; + } + + double RetrieveAnimationsVisitor::parseTimeSignature(const std::string& line) + { + size_t spacePos = line.find_last_of(' '); + double time = 0.0; + if (spacePos != std::string::npos && spacePos + 1 < line.size()) + time = std::stod(line.substr(spacePos + 1)); + return time; + } + + std::string RetrieveAnimationsVisitor::changeFileExtension(const std::string file, const std::string ext) + { + size_t extPos = file.find_last_of('.'); + if (extPos != std::string::npos && extPos+1 < file.size()) + { + return file.substr(0, extPos + 1) + ext; + } + return file; + } + } namespace Resource @@ -110,7 +154,7 @@ namespace Resource osg::ref_ptr bam = dynamic_cast (scene->getUpdateCallback()); if (bam) { - Resource::RetrieveAnimationsVisitor rav(*loaded.get(), bam); + Resource::RetrieveAnimationsVisitor rav(*loaded.get(), bam, normalized, mVFS); scene->accept(rav); } } diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp index 3e992ac5e..87a20b97a 100644 --- a/components/resource/keyframemanager.hpp +++ b/components/resource/keyframemanager.hpp @@ -15,13 +15,21 @@ namespace Resource class RetrieveAnimationsVisitor : public osg::NodeVisitor { public: - RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr animationManager); + RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr animationManager, + const std::string& normalized, const VFS::Manager* vfs); virtual void apply(osg::Node& node) override; private: + + std::string changeFileExtension(const std::string file, const std::string ext); + std::string parseTextKey(const std::string& line); + double parseTimeSignature(const std::string& line); + SceneUtil::KeyframeHolder& mTarget; osg::ref_ptr mAnimationManager; + std::string mNormalized; + const VFS::Manager* mVFS; }; } From 303f1912a6af88e49f96fc8260621a8e7519e48a Mon Sep 17 00:00:00 2001 From: unelsson Date: Thu, 4 Feb 2021 23:14:52 +0200 Subject: [PATCH 22/40] less debug spam --- components/resource/keyframemanager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 923ce4326..0c33428e0 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -74,7 +74,6 @@ namespace Resource std::string line; while ( getline (*textKeysFile, line) ) { - Log(Debug::Warning) << "add textkey ***" << parseTextKey(line) << "***" << parseTimeSignature(line) << "***"; mTarget.mTextKeys.emplace(parseTimeSignature(line), std::move(parseTextKey(line))); } } From e42b67ee50b8d5950e183db51d750198d87db7f2 Mon Sep 17 00:00:00 2001 From: Noah Gooder Date: Fri, 5 Feb 2021 17:59:36 +0000 Subject: [PATCH 23/40] Modified actors.cpp and Authors.md --- AUTHORS.md | 1 + apps/openmw/mwmechanics/actors.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index e6ff67293..53efdd286 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -215,6 +215,7 @@ Programmers Yohaulticetl Yuri Krupenin zelurker + Noah Gooder Documentation ------------- diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cb3570d21..c0a137158 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -951,7 +951,7 @@ namespace MWMechanics if (actor.getClass().hasInventoryStore(actor)) actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Poison); } - else if (effects.get(ESM::MagicEffect::CureParalyzation).getModifier() > 0) + if (effects.get(ESM::MagicEffect::CureParalyzation).getModifier() > 0) { creatureStats.getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze); creatureStats.getSpells().purgeEffect(ESM::MagicEffect::Paralyze); From 3007cb14a9fa10ef2d17f53a2519030135d737db Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Fri, 5 Feb 2021 19:00:35 +0100 Subject: [PATCH 24/40] Also allow negative AI values in dialogue --- CHANGELOG.md | 1 + apps/openmw/mwdialogue/filter.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5b66ee01..d25984a83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ Bug #5762: Movement solver is insufficiently robust Bug #5821: NPCs from mods getting removed if mod order was changed Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee + Bug #5836: OpenMW dialogue/greeting/voice filter doesn't accept negative Ai values for NPC's hello, alarm, fight, and flee Feature #390: 3rd person look "over the shoulder" Feature #1536: Show more information about level on menu Feature #2386: Distant Statics in the form of Object Paging diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index a3c326ab8..334a9db39 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -316,7 +316,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con case SelectWrapper::Function_AiSetting: return mActor.getClass().getCreatureStats (mActor).getAiSetting ( - (MWMechanics::CreatureStats::AiSetting)select.getArgument()).getModified(); + (MWMechanics::CreatureStats::AiSetting)select.getArgument()).getModified(false); case SelectWrapper::Function_PcAttribute: From 3e273a759acc8e238de5ce2ceb03d877405a6f0f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 6 Feb 2021 16:41:46 +0000 Subject: [PATCH 25/40] Clarify method name now we're using it differently --- components/sceneutil/mwshadowtechnique.cpp | 6 +++--- components/sceneutil/mwshadowtechnique.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 7476bc219..ba903f6db 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1426,7 +1426,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) if (numValidShadows>0) { - selectStateSetForRenderingShadow(*vdd, cv.getTraversalNumber()); + prepareStateSetForRenderingShadow(*vdd, cv.getTraversalNumber()); } // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()< stateset = vdd.getStateSet(traversalNumber); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 5125247dd..7b934b798 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -231,7 +231,7 @@ namespace SceneUtil { virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; - virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd, unsigned int traversalNumber) const; + virtual osg::StateSet* prepareStateSetForRenderingShadow(ViewDependentData& vdd, unsigned int traversalNumber) const; protected: virtual ~MWShadowTechnique(); From 6aa75c287aa86e7e1c44cd7cd15ae89cef0894c8 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 7 Feb 2021 00:15:01 +0100 Subject: [PATCH 26/40] Don't check magicka when casting free spells --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/spellutil.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa74164d9..3e29a292f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ Bug #5758: Paralyzed actors behavior is inconsistent with vanilla Bug #5762: Movement solver is insufficiently robust Bug #5821: NPCs from mods getting removed if mod order was changed + Bug #5841: Can't Cast Zero Cost Spells When Magicka is < 0 Feature #390: 3rd person look "over the shoulder" Feature #1536: Show more information about level on menu Feature #2386: Distant Statics in the form of Object Paging diff --git a/apps/openmw/mwmechanics/spellutil.cpp b/apps/openmw/mwmechanics/spellutil.cpp index 8b2f5c46c..0c667e680 100644 --- a/apps/openmw/mwmechanics/spellutil.cpp +++ b/apps/openmw/mwmechanics/spellutil.cpp @@ -123,7 +123,7 @@ namespace MWMechanics if (spell->mData.mType != ESM::Spell::ST_Spell) return 100; - if (checkMagicka && stats.getMagicka().getCurrent() < spell->mData.mCost) + if (checkMagicka && spell->mData.mCost > 0 && stats.getMagicka().getCurrent() < spell->mData.mCost) return 0; if (spell->mData.mFlags & ESM::Spell::F_Always) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 442672d2b..d21c17a51 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3009,7 +3009,7 @@ namespace MWWorld // Check mana bool godmode = (isPlayer && mGodMode); MWMechanics::DynamicStat magicka = stats.getMagicka(); - if (magicka.getCurrent() < spell->mData.mCost && !godmode) + if (spell->mData.mCost > 0 && magicka.getCurrent() < spell->mData.mCost && !godmode) { message = "#{sMagicInsufficientSP}"; fail = true; From 31b5150e0db3f2094d4ac4a67990a82529c69a83 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sun, 7 Feb 2021 09:12:38 +0100 Subject: [PATCH 27/40] Fix implementation of Misc::swapEndiannessInplace --- components/misc/endianness.hpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/components/misc/endianness.hpp b/components/misc/endianness.hpp index 1b43e584e..8019d33ed 100644 --- a/components/misc/endianness.hpp +++ b/components/misc/endianness.hpp @@ -2,6 +2,8 @@ #define COMPONENTS_MISC_ENDIANNESS_H #include +#include +#include namespace Misc { @@ -15,20 +17,26 @@ namespace Misc if constexpr (sizeof(T) == 2) { - uint16_t& v16 = *reinterpret_cast(&v); + uint16_t v16; + std::memcpy(&v16, &v, sizeof(T)); v16 = (v16 >> 8) | (v16 << 8); + std::memcpy(&v, &v16, sizeof(T)); } if constexpr (sizeof(T) == 4) { - uint32_t& v32 = *reinterpret_cast(&v); - v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) || v32 << 24; + uint32_t v32; + std::memcpy(&v32, &v, sizeof(T)); + v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) | v32 << 24; + std::memcpy(&v, &v32, sizeof(T)); } if constexpr (sizeof(T) == 8) { - uint64_t& v64 = *reinterpret_cast(&v); + uint64_t v64; + std::memcpy(&v64, &v, sizeof(T)); v64 = (v64 >> 56) | ((v64 & 0x00ff'0000'0000'0000) >> 40) | ((v64 & 0x0000'ff00'0000'0000) >> 24) | ((v64 & 0x0000'00ff'0000'0000) >> 8) | ((v64 & 0x0000'0000'ff00'0000) << 8) | ((v64 & 0x0000'0000'00ff'0000) << 24) | ((v64 & 0x0000'0000'0000'ff00) << 40) | (v64 << 56); + std::memcpy(&v, &v64, sizeof(T)); } } From f1caeea4445cbe8c0b235203867a86512cd5f120 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 7 Feb 2021 11:58:23 +0100 Subject: [PATCH 28/40] Don't return negative values from GetMagicka --- apps/openmw/mwscript/statsextensions.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 58a943e1a..ab3287c9a 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -187,6 +187,9 @@ namespace MWScript .getCreatureStats(ptr) .getDynamic(mIndex) .getCurrent(); + // GetMagicka shouldn't return negative values + if(mIndex == 1 && value < 0) + value = 0; } runtime.push (value); } From 39c2c19daee5d4cff5379a077bdee4d75ab07d7a Mon Sep 17 00:00:00 2001 From: Jonas Tobias Hopusch Date: Sun, 7 Feb 2021 12:53:06 +0100 Subject: [PATCH 29/40] Update 'toggle sneak' documentation The docs now correctly say that this setting can be changed in the launcher, instead of insisting it's a config-file-only setting. Closes #5844 Signed-off-by: Jonas Tobias Hopusch --- CHANGELOG.md | 1 + docs/source/reference/modding/settings/input.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d25984a83..20932c89f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,6 +132,7 @@ Feature #5813: Instanced groundcover support Task #5480: Drop Qt4 support Task #5520: Improve cell name autocompleter implementation + Task #5844: Update 'toggle sneak' documentation 0.46.0 ------ diff --git a/docs/source/reference/modding/settings/input.rst b/docs/source/reference/modding/settings/input.rst index 8a95686cf..d04c267a7 100644 --- a/docs/source/reference/modding/settings/input.rst +++ b/docs/source/reference/modding/settings/input.rst @@ -38,7 +38,7 @@ This setting causes the behavior of the sneak key (bound to Ctrl by default) to toggle sneaking on and off rather than requiring the key to be held down while sneaking. Players that spend significant time sneaking may find the character easier to control with this option enabled. -This setting can only be configured by editing the settings configuration file. +This setting can be toggled in the launcher under "Advanced" -> "Game Mechanics" -> "Toggle sneak". always run ---------- From af0f94f03e373f79823a86fa40e59de9fbfa0788 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 7 Feb 2021 12:55:10 +0100 Subject: [PATCH 30/40] Play damage sound when hurt by elemental shields --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/combat.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d25984a83..6c4c241b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,7 @@ Bug #5821: NPCs from mods getting removed if mod order was changed Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee Bug #5836: OpenMW dialogue/greeting/voice filter doesn't accept negative Ai values for NPC's hello, alarm, fight, and flee + Bug #5840: GetSoundPlaying "Health Damage" doesn't play when NPC hits target with shield effect ( vanilla engine behavior ) Feature #390: 3rd person look "over the shoulder" Feature #1536: Show more information about level on menu Feature #2386: Distant Statics in the form of Object Paging diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 183845b8c..fd3f31811 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -345,6 +345,8 @@ namespace MWMechanics MWMechanics::DynamicStat health = attackerStats.getHealth(); health.setCurrent(health.getCurrent() - x); attackerStats.setHealth(health); + + MWBase::Environment::get().getSoundManager()->playSound3D(attacker, "Health Damage", 1.0f, 1.0f); } } From b78820de5563c92184d31c1d44af122b4b830364 Mon Sep 17 00:00:00 2001 From: fredzio Date: Sun, 7 Feb 2021 18:32:03 +0100 Subject: [PATCH 31/40] Ignore projectiles inside of MovementSolver::unstuck. It is normal for actors to be inside of a projectile collision shape. A side effect of moving actors outside of projectile collision shape is that if both the actor and the projectile are near a wall, the actor could get moved outside of the world. --- apps/openmw/mwphysics/movementsolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp index 9d2957409..5f0322a1f 100644 --- a/apps/openmw/mwphysics/movementsolver.cpp +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -38,7 +38,7 @@ namespace MWPhysics ContactCollectionCallback(const btCollisionObject * me, osg::Vec3f velocity) : mMe(me) { m_collisionFilterGroup = me->getBroadphaseHandle()->m_collisionFilterGroup; - m_collisionFilterMask = me->getBroadphaseHandle()->m_collisionFilterMask; + m_collisionFilterMask = me->getBroadphaseHandle()->m_collisionFilterMask & ~CollisionType_Projectile; mVelocity = Misc::Convert::toBullet(velocity); } btScalar addSingleResult(btManifoldPoint & contact, const btCollisionObjectWrapper * colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper * colObj1Wrap, int partId1, int index1) override From da6223fc4b7f5bb98143b6a5bd1585ce93fd9a92 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 7 Feb 2021 23:27:45 +0000 Subject: [PATCH 32/40] Use default icon.tga when inventory icon is missing --- apps/openmw/mwgui/itemwidget.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 940e95a7e..7c7fa8828 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -6,6 +6,9 @@ #include // correctIconPath +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -106,7 +109,10 @@ namespace MWGui std::string invIcon = ptr.getClass().getInventoryIcon(ptr); if (invIcon.empty()) invIcon = "default icon.tga"; - setIcon(MWBase::Environment::get().getWindowManager()->correctIconPath(invIcon)); + invIcon = MWBase::Environment::get().getWindowManager()->correctIconPath(invIcon); + if (!MWBase::Environment::get().getResourceSystem()->getVFS()->exists(invIcon)) + invIcon = MWBase::Environment::get().getWindowManager()->correctIconPath("default icon.tga"); + setIcon(invIcon); } From 034a7a9dbca2094e3e76bcd075b06ea30ca03ddd Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 7 Feb 2021 23:45:53 +0000 Subject: [PATCH 33/40] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b88e9ee8..83ad5725e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,6 +109,7 @@ Feature #2686: Timestamps in openmw.log Feature #3171: OpenMW-CS: Instance drag selection Feature #4894: Consider actors as obstacles for pathfinding + Feature #4977: Use the "default icon.tga" when an item's icon is not found Feature #5043: Head Bobbing Feature #5199: Improve Scene Colors Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher From f3271cb66b1222cfbce3a588858c5b0fe004dcf7 Mon Sep 17 00:00:00 2001 From: Sergey Fukanchik Date: Tue, 9 Feb 2021 13:09:36 -0500 Subject: [PATCH 34/40] Add unit test for swapEndiannessInplace(). Part of Bug #5837 --- apps/openmw_test_suite/CMakeLists.txt | 1 + .../misc/test_endianness.cpp | 122 ++++++++++++++++++ components/misc/endianness.hpp | 2 +- 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 apps/openmw_test_suite/misc/test_endianness.cpp diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 5658a5eef..a3bb0c6f8 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -15,6 +15,7 @@ if (GTEST_FOUND AND GMOCK_FOUND) esm/test_fixed_string.cpp misc/test_stringops.cpp + misc/test_endianness.cpp nifloader/testbulletnifloader.cpp diff --git a/apps/openmw_test_suite/misc/test_endianness.cpp b/apps/openmw_test_suite/misc/test_endianness.cpp new file mode 100644 index 000000000..240e4a49a --- /dev/null +++ b/apps/openmw_test_suite/misc/test_endianness.cpp @@ -0,0 +1,122 @@ +#include +#include "components/misc/endianness.hpp" + +struct EndiannessTest : public ::testing::Test {}; + +TEST_F(EndiannessTest, test_swap_endianness_inplace1) +{ + uint8_t zero=0x00; + uint8_t ff=0xFF; + uint8_t fortytwo=0x42; + uint8_t half=128; + + Misc::swapEndiannessInplace(zero); + EXPECT_EQ(zero, 0x00); + + Misc::swapEndiannessInplace(ff); + EXPECT_EQ(ff, 0xFF); + + Misc::swapEndiannessInplace(fortytwo); + EXPECT_EQ(fortytwo, 0x42); + + Misc::swapEndiannessInplace(half); + EXPECT_EQ(half, 128); +} + +TEST_F(EndiannessTest, test_swap_endianness_inplace2) +{ + uint16_t zero = 0x0000; + uint16_t ffff = 0xFFFF; + uint16_t n12 = 0x0102; + uint16_t fortytwo = 0x0042; + + Misc::swapEndiannessInplace(zero); + EXPECT_EQ(zero, 0x0000); + Misc::swapEndiannessInplace(zero); + EXPECT_EQ(zero, 0x0000); + + Misc::swapEndiannessInplace(ffff); + EXPECT_EQ(ffff, 0xFFFF); + Misc::swapEndiannessInplace(ffff); + EXPECT_EQ(ffff, 0xFFFF); + + Misc::swapEndiannessInplace(n12); + EXPECT_EQ(n12, 0x0201); + Misc::swapEndiannessInplace(n12); + EXPECT_EQ(n12, 0x0102); + + Misc::swapEndiannessInplace(fortytwo); + EXPECT_EQ(fortytwo, 0x4200); + Misc::swapEndiannessInplace(fortytwo); + EXPECT_EQ(fortytwo, 0x0042); +} + +TEST_F(EndiannessTest, test_swap_endianness_inplace4) +{ + uint32_t zero = 0x00000000; + uint32_t n1234 = 0x01020304; + uint32_t ffff = 0xFFFFFFFF; + + Misc::swapEndiannessInplace(zero); + EXPECT_EQ(zero, 0x00000000); + Misc::swapEndiannessInplace(zero); + EXPECT_EQ(zero, 0x00000000); + + Misc::swapEndiannessInplace(n1234); + EXPECT_EQ(n1234, 0x04030201); + Misc::swapEndiannessInplace(n1234); + EXPECT_EQ(n1234, 0x01020304); + + Misc::swapEndiannessInplace(ffff); + EXPECT_EQ(ffff, 0xFFFFFFFF); + Misc::swapEndiannessInplace(ffff); + EXPECT_EQ(ffff, 0xFFFFFFFF); +} + +TEST_F(EndiannessTest, test_swap_endianness_inplace8) +{ + uint64_t zero = 0x0000'0000'0000'0000; + uint64_t n1234 = 0x0102'0304'0506'0708; + uint64_t ffff = 0xFFFF'FFFF'FFFF'FFFF; + + Misc::swapEndiannessInplace(zero); + EXPECT_EQ(zero, 0x0000'0000'0000'0000); + Misc::swapEndiannessInplace(zero); + EXPECT_EQ(zero, 0x0000'0000'0000'0000); + + Misc::swapEndiannessInplace(ffff); + EXPECT_EQ(ffff, 0xFFFF'FFFF'FFFF'FFFF); + Misc::swapEndiannessInplace(ffff); + EXPECT_EQ(ffff, 0xFFFF'FFFF'FFFF'FFFF); + + Misc::swapEndiannessInplace(n1234); + EXPECT_EQ(n1234, 0x0807'0605'0403'0201); + Misc::swapEndiannessInplace(n1234); + EXPECT_EQ(n1234, 0x0102'0304'0506'0708); +} + +TEST_F(EndiannessTest, test_swap_endianness_inplace_float) +{ + const uint32_t original = 0x4023d70a; + const uint32_t expected = 0x0ad72340; + + float number; + memcpy(&number, &original, sizeof(original)); + + Misc::swapEndiannessInplace(number); + + EXPECT_TRUE(!memcmp(&number, &expected, sizeof(expected))); +} + +TEST_F(EndiannessTest, test_swap_endianness_inplace_double) +{ + const uint64_t original = 0x040047ae147ae147ul; + const uint64_t expected = 0x47e17a14ae470004ul; + + double number; + memcpy(&number, &original, sizeof(original)); + + Misc::swapEndiannessInplace(number); + + EXPECT_TRUE(!memcmp(&number, &expected, sizeof(expected)) ); +} diff --git a/components/misc/endianness.hpp b/components/misc/endianness.hpp index 8019d33ed..ad8aba18c 100644 --- a/components/misc/endianness.hpp +++ b/components/misc/endianness.hpp @@ -26,7 +26,7 @@ namespace Misc { uint32_t v32; std::memcpy(&v32, &v, sizeof(T)); - v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) | v32 << 24; + v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) | (v32 << 24); std::memcpy(&v, &v32, sizeof(T)); } if constexpr (sizeof(T) == 8) From f8f6d63d4c34d0284123e664dfcdcde6db7b1c15 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 9 Feb 2021 21:56:21 +0000 Subject: [PATCH 35/40] Optimise groundcover lighting --- files/shaders/lighting.glsl | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 5eae89029..a2dcc758a 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -13,22 +13,13 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie #ifndef GROUNDCOVER lambert = max(lambert, 0.0); #else + float eyeCosine = dot(normalize(viewPos), viewNormal.xyz); + if (lambert < 0.0) { - float cosine = dot(normalize(viewPos), normalize(viewNormal.xyz)); - if (lambert >= 0.0) - cosine = -cosine; - - float mult = 1.0; - float divisor = 8.0; - - if (cosine < 0.0 && cosine >= -1.0/divisor) - mult = mix(1.0, 0.3, -cosine*divisor); - else if (cosine < -1.0/divisor) - mult = 0.3; - - lambert *= mult; - lambert = abs(lambert); + lambert = -lambert; + eyeCosine = -eyeCosine; } + lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0); #endif diffuseOut = gl_LightSource[lightIndex].diffuse.xyz * lambert; } From 2e73d2c1451f080d854b51de89ce77893ebbf67d Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 10 Feb 2021 22:13:04 +0100 Subject: [PATCH 36/40] Fallback to default cell name for door destination --- CHANGELOG.md | 1 + apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/door.cpp | 27 ++++++--------------------- apps/openmw/mwworld/worldimp.cpp | 16 +++++++++++----- apps/openmw/mwworld/worldimp.hpp | 1 + 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83ad5725e..acfdc9e50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,7 @@ Bug #5821: NPCs from mods getting removed if mod order was changed Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee Bug #5836: OpenMW dialogue/greeting/voice filter doesn't accept negative Ai values for NPC's hello, alarm, fight, and flee + Bug #5838: Local map and other menus become blank in some locations while playing Wizards' Islands mod. Bug #5840: GetSoundPlaying "Health Damage" doesn't play when NPC hits target with shield effect ( vanilla engine behavior ) Bug #5841: Can't Cast Zero Cost Spells When Magicka is < 0 Feature #390: 3rd person look "over the shoulder" diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a3b035a8d..194e8f695 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -185,6 +185,7 @@ namespace MWBase /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. + virtual std::string getCellName(const ESM::Cell* cell) const = 0; virtual void removeRefScript (MWWorld::RefData *ref) = 0; //< Remove the script attached to ref from mLocalScripts diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index ba51d9c2b..25f7fc456 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -302,30 +302,15 @@ namespace MWClass std::string Door::getDestination (const MWWorld::LiveCellRef& door) { - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - - std::string dest; - if (door.mRef.getDestCell() != "") - { - // door leads to an interior, use interior name as tooltip - dest = door.mRef.getDestCell(); - } - else + std::string dest = door.mRef.getDestCell(); + if (dest.empty()) { // door leads to exterior, use cell name (if any), otherwise translated region name int x,y; - MWBase::Environment::get().getWorld()->positionToIndex (door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1], x, y); - const ESM::Cell* cell = store.get().find(x,y); - if (cell->mName != "") - dest = cell->mName; - else - { - const ESM::Region* region = - store.get().find(cell->mRegion); - - //name as is, not a token - return MyGUI::TextIterator::toTagsString(region->mName); - } + auto world = MWBase::Environment::get().getWorld(); + world->positionToIndex (door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1], x, y); + const ESM::Cell* cell = world->getStore().get().search(x,y); + dest = world->getCellName(cell); } return "#{sCell=" + dest + "}"; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d21c17a51..651d93ec5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -656,13 +656,19 @@ namespace MWWorld { if (!cell) cell = mWorldScene->getCurrentCell(); + return getCellName(cell->getCell()); + } - if (!cell->getCell()->isExterior() || !cell->getCell()->mName.empty()) - return cell->getCell()->mName; - - if (const ESM::Region* region = mStore.get().search (cell->getCell()->mRegion)) - return region->mName; + std::string World::getCellName(const ESM::Cell* cell) const + { + if (cell) + { + if (!cell->isExterior() || !cell->mName.empty()) + return cell->mName; + if (const ESM::Region* region = mStore.get().search (cell->mRegion)) + return region->mName; + } return mStore.get().find ("sDefaultCellname")->mValue.getString(); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 29d29a160..bc2baafd8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -281,6 +281,7 @@ namespace MWWorld /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. + std::string getCellName(const ESM::Cell* cell) const override; void removeRefScript (MWWorld::RefData *ref) override; //< Remove the script attached to ref from mLocalScripts From c4e909c29e4f1bbb4c463bc015daf42610ad6ec5 Mon Sep 17 00:00:00 2001 From: fredzio Date: Fri, 12 Feb 2021 19:36:03 +0100 Subject: [PATCH 37/40] Silence a clang warning: warning: moving a temporary object prevents copy elision [-Wpessimizing-move] --- components/resource/keyframemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 0c33428e0..f4ab79519 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -74,7 +74,7 @@ namespace Resource std::string line; while ( getline (*textKeysFile, line) ) { - mTarget.mTextKeys.emplace(parseTimeSignature(line), std::move(parseTextKey(line))); + mTarget.mTextKeys.emplace(parseTimeSignature(line), parseTextKey(line)); } } catch (std::exception& e) From 0736fec148fa68680a54a928c7fdc186bca9bab5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 12 Feb 2021 19:21:07 +0000 Subject: [PATCH 38/40] Give binaries static filename --- .gitlab-ci.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 810e23d38..2c45e19e6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -116,12 +116,13 @@ variables: &cs-targets - .\ActivateMSVC.ps1 - cmake --build . --config $config --target ($targets.Split(',')) - cd $config + - echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt - | if (Get-ChildItem -Recurse *.pdb) { - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' + 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt Get-ChildItem -Recurse *.pdb | Remove-Item } - - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*' + - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}.zip '*' after_script: - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log cache: @@ -206,12 +207,13 @@ Windows_Ninja_CS_RelWithDebInfo: - cd MSVC2019_64 - cmake --build . --config $config --target ($targets.Split(',')) - cd $config + - echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt - | if (Get-ChildItem -Recurse *.pdb) { - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' + 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt Get-ChildItem -Recurse *.pdb | Remove-Item } - - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*' + - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}.zip '*' after_script: - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log cache: From 5e5c0a1d8982fad48dbed3784da59201ba3954aa Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 13 Feb 2021 00:28:18 +0000 Subject: [PATCH 39/40] Add branch name back to filename The URL needs to contain the branch name anyway, so there's no point removing it. --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2c45e19e6..6bfe0bf23 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -122,7 +122,7 @@ variables: &cs-targets 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt Get-ChildItem -Recurse *.pdb | Remove-Item } - - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}.zip '*' + - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}.zip '*' after_script: - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log cache: @@ -213,7 +213,7 @@ Windows_Ninja_CS_RelWithDebInfo: 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt Get-ChildItem -Recurse *.pdb | Remove-Item } - - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}.zip '*' + - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}.zip '*' after_script: - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log cache: From e7afbc74d82351e59e671343f2a9f40a7603c4e5 Mon Sep 17 00:00:00 2001 From: uramer Date: Wed, 27 Jan 2021 20:57:11 +0100 Subject: [PATCH 40/40] Wizard: Only allow to select Morrowind.esm master files, display an error if Morrowind.bsa is missing --- apps/wizard/existinginstallationpage.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/wizard/existinginstallationpage.cpp b/apps/wizard/existinginstallationpage.cpp index 2434f42cf..886fcd95d 100644 --- a/apps/wizard/existinginstallationpage.cpp +++ b/apps/wizard/existinginstallationpage.cpp @@ -95,9 +95,9 @@ void Wizard::ExistingInstallationPage::on_browseButton_clicked() { QString selectedFile = QFileDialog::getOpenFileName( this, - tr("Select master file"), + tr("Select Morrowind.esm (located in Data Files)"), QDir::currentPath(), - QString(tr("Morrowind master file (*.esm)")), + QString(tr("Morrowind master file (Morrowind.esm)")), nullptr, QFileDialog::DontResolveSymlinks); @@ -110,7 +110,18 @@ void Wizard::ExistingInstallationPage::on_browseButton_clicked() return; if (!mWizard->findFiles(QLatin1String("Morrowind"), info.absolutePath())) - return; // No valid Morrowind installation found + { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error detecting Morrowind files")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr( + "Morrowind.bsa is missing!
\ + Make sure your Morrowind installation is complete." + )); + msgBox.exec(); + return; + } QString path(QDir::toNativeSeparators(info.absolutePath())); QList items = installationsList->findItems(path, Qt::MatchExactly);