From 3194520dcd5eecb04540af0fc936bd303b38c566 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 30 Dec 2020 22:11:32 +0200 Subject: [PATCH 01/17] 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/17] 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 7d3f2bc113aed491a004abab576e7871788eb400 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 2 Feb 2021 17:33:40 +0200 Subject: [PATCH 03/17] 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 04/17] 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 05/17] 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 06/17] Update base_anim file settings --- files/settings-default.cfg | 61 ++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 16 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,6 +955,51 @@ defer aabb update = true # Loading arbitrary meshes is not advised and may cause instability. load unsupported nif files = false +# 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 @@ -969,19 +1014,3 @@ 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 1221889cf7c099ae0b00e7752b24448a1deac9e0 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Tue, 2 Feb 2021 21:41:17 +0200 Subject: [PATCH 07/17] 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 08/17] \ 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 09/17] 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 10/17] 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 11/17] 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 12/17] 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 13/17] 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 e91d1a2b42aa3b28e5f86acc83201702c08cc2b7 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 3 Feb 2021 21:16:26 +0200 Subject: [PATCH 14/17] 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 15/17] 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 d5844b098295389c3b757a5a3c54f0627780d59b Mon Sep 17 00:00:00 2001 From: unelsson Date: Thu, 4 Feb 2021 23:14:21 +0200 Subject: [PATCH 16/17] 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 17/17] 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))); } }