From ead73fce312a215374fecde6f401761b87f7e793 Mon Sep 17 00:00:00 2001 From: Wolfgang Lieff Date: Tue, 29 Mar 2022 21:47:37 +0200 Subject: [PATCH 1/5] initial NiFltAnimationNode support --- apps/openmw/mwrender/objectpaging.cpp | 13 +++++++++++++ components/nif/niffile.cpp | 1 + components/nif/node.hpp | 11 +++++++++++ components/nif/record.hpp | 1 + components/nifosg/nifloader.cpp | 19 +++++++++++++++++++ components/sceneutil/optimizer.cpp | 16 +++++++++++++++- components/sceneutil/optimizer.hpp | 2 ++ 7 files changed, 62 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 4748491dd4..4865f1088e 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -152,6 +153,13 @@ namespace MWRender n->setDataVariance(osg::Object::STATIC); return n; } + if (const osg::Sequence* sq = dynamic_cast(node)) + { + osg::Group* n = new osg::Group; + n->addChild(operator()(sq->getChild(sq->getValue()))); + n->setDataVariance(osg::Object::STATIC); + return n; + } mNodePath.push_back(node); @@ -301,6 +309,11 @@ namespace MWRender traverse(*lod->getChild(i)); return; } + if (osg::Sequence* sq = dynamic_cast(&node)) + { + traverse(*sq->getChild(sq->getValue())); + return; + } traverse(node); } diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 0a1acde5b5..57d1ce6457 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -36,6 +36,7 @@ static std::map makeFactory() {"NiNode" , &construct }, {"NiSwitchNode" , &construct }, {"NiLODNode" , &construct }, + {"NiFltAnimationNode" , &construct }, {"AvoidNode" , &construct }, {"NiCollisionSwitch" , &construct }, {"NiBSParticleNode" , &construct }, diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 34ac12e490..6452e2b8af 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -431,6 +431,17 @@ struct NiLODNode : public NiSwitchNode } }; +struct NiFltAnimationNode : public NiSwitchNode +{ + float Interval; + + void read(NIFStream *nif) override + { + NiSwitchNode::read(nif); + Interval = nif->getFloat(); + } +}; + // Abstract struct NiAccumulator : Record { diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 133c393ab5..37084af44e 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -38,6 +38,7 @@ enum RecordType RC_NiNode, RC_NiSwitchNode, RC_NiLODNode, + RC_NiFltAnimationNode, RC_NiBillboardNode, RC_AvoidNode, RC_NiCollisionSwitch, diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 3007bc6cf2..9d66d3f4b6 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -416,6 +417,17 @@ namespace NifOsg return switchNode; } + static osg::ref_ptr handleSequenceNode(const Nif::NiFltAnimationNode* niFltAnimationNode) + { + osg::ref_ptr sequenceNode (new osg::Sequence); + sequenceNode->setName(niFltAnimationNode->name); + sequenceNode->setDefaultTime(niFltAnimationNode->Interval); + sequenceNode->setInterval(osg::Sequence::LOOP, 0,-1); + sequenceNode->setDuration( -1.0f, -1); + sequenceNode->setMode(osg::Sequence::START); + return sequenceNode; + } + osg::ref_ptr handleSourceTexture(const Nif::NiSourceTexture* st, Resource::ImageManager* imageManager) { if (!st) @@ -711,6 +723,13 @@ namespace NifOsg node->addChild(lodNode); currentNode = lodNode; } + else if (nifNode->recType == Nif::RC_NiFltAnimationNode) + { + const Nif::NiFltAnimationNode* niFltAnimationNode = static_cast(nifNode); + osg::ref_ptr sequenceNode = handleSequenceNode(niFltAnimationNode); + node->addChild(sequenceNode); + currentNode = sequenceNode; + } const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index 748ceee952..00e113afb9 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -845,7 +846,7 @@ void Optimizer::RemoveEmptyNodesVisitor::removeEmptyNodes() ++pitr) { osg::Group* parent = *pitr; - if (!parent->asSwitch() && !dynamic_cast(parent)) + if (!parent->asSwitch() && !dynamic_cast(parent) && !dynamic_cast(parent)) { parent->removeChild(nodeToRemove.get()); if (parent->getNumChildren()==0 && isOperationPermissibleForObject(parent)) newEmptyGroups.insert(parent); @@ -887,6 +888,13 @@ void Optimizer::RemoveRedundantNodesVisitor::apply(osg::Switch& switchNode) traverse(*switchNode.getChild(i)); } +void Optimizer::RemoveRedundantNodesVisitor::apply(osg::Sequence& sequenceNode) +{ + // We should keep all sequence child nodes since they reflect different sequence states. + for (unsigned int i=0; i Date: Wed, 30 Mar 2022 09:27:00 +0200 Subject: [PATCH 2/5] refactor to use mInternal, support Flag_Reverse and updated changelog/authors.md --- AUTHORS.md | 5 +++-- CHANGELOG.md | 3 ++- apps/openmw/mwrender/objectpaging.cpp | 3 +-- components/nif/node.hpp | 9 +++++++-- components/nifosg/nifloader.cpp | 8 +++++--- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 84f465414e..264ffe2668 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -164,6 +164,7 @@ Programmers Nialsy Nick Crawford (nighthawk469) Nikolay Kasyanov (corristo) + Noah Gooder nobrakal Nolan Poe (nopoe) Nurivan Gomez (Nuri-G) @@ -228,14 +229,14 @@ Programmers viadanna Vincent Heuken Vladimir Panteleev (CyberShadow) + vocollapse Wang Ryu (bzzt) Will Herrmann (Thunderforge) - vocollapse + Wolfgang Lieff xyzz Yohaulticetl Yuri Krupenin zelurker - Noah Gooder Documentation ------------- diff --git a/CHANGELOG.md b/CHANGELOG.md index 03777cbf87..952dce3495 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -138,11 +138,12 @@ Feature #6288: Preserve the "blocked" record flag for referenceable objects. Feature #6380: Commas are treated as whitespace in vanilla Feature #6419: Topics shouldn't be greyed out if they can produce another topic reference - Feature #6443: NiStencilProperty is not fully supported + Feature #6443: Support NiStencilProperty Feature #6534: Shader-based object texture blending Feature #6541: Gloss-mapping Feature #6592: Missing support for NiTriShape particle emitters Feature #6600: Support NiSortAdjustNode + Feature #6684: Support NiFltAnimationNode Task #6201: Remove the "Note: No relevant classes found. No output generated" warnings Task #6264: Remove the old classes in animation.cpp Task #6553: Simplify interpreter instruction registration diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 4865f1088e..57040eca98 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -2,7 +2,6 @@ #include -#include #include #include #include @@ -66,7 +65,7 @@ namespace MWRender case ESM::REC_CONT: return store.get().searchStatic(id)->mModel; default: - return std::string(); + return {}; } } diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 6452e2b8af..2f64e39a75 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -433,12 +433,17 @@ struct NiLODNode : public NiSwitchNode struct NiFltAnimationNode : public NiSwitchNode { - float Interval; + float mInterval; + enum Flags + { + Flag_Reverse = 0x40 + }; + void read(NIFStream *nif) override { NiSwitchNode::read(nif); - Interval = nif->getFloat(); + mInterval = nif->getFloat(); } }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9d66d3f4b6..8406db3839 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -421,10 +421,12 @@ namespace NifOsg { osg::ref_ptr sequenceNode (new osg::Sequence); sequenceNode->setName(niFltAnimationNode->name); - sequenceNode->setDefaultTime(niFltAnimationNode->Interval); - sequenceNode->setInterval(osg::Sequence::LOOP, 0,-1); - sequenceNode->setDuration( -1.0f, -1); + sequenceNode->setDefaultTime(niFltAnimationNode->mInterval); sequenceNode->setMode(osg::Sequence::START); + if (!niFltAnimationNode->flags & Nif::NiFltAnimationNode::Flag_Reverse) + sequenceNode->setDuration(-1.0f, -1); + else + sequenceNode->setDuration(1.0f, -1); return sequenceNode; } From af41560c3fc67d6113a4ab58d66a994a02dbfe2b Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 30 Mar 2022 15:51:21 +0200 Subject: [PATCH 3/5] reverse the reverse flag check; set duration to 0.2f which matches openmw to morrowind speed which is measured in 1/5 seconds --- components/nifosg/nifloader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 8406db3839..9cd2685747 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -423,10 +423,10 @@ namespace NifOsg sequenceNode->setName(niFltAnimationNode->name); sequenceNode->setDefaultTime(niFltAnimationNode->mInterval); sequenceNode->setMode(osg::Sequence::START); - if (!niFltAnimationNode->flags & Nif::NiFltAnimationNode::Flag_Reverse) - sequenceNode->setDuration(-1.0f, -1); + if (niFltAnimationNode->flags & Nif::NiFltAnimationNode::Flag_Reverse) + sequenceNode->setDuration(0.2f, -1); else - sequenceNode->setDuration(1.0f, -1); + sequenceNode->setDuration(-0.2f, -1); return sequenceNode; } From c376f3793e1bdc52600efa68e2924c0d3910625e Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 31 Mar 2022 21:55:14 +0200 Subject: [PATCH 4/5] check that the index is now -1; otherwise bad things happen --- apps/openmw/mwrender/objectpaging.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 57040eca98..d2b66b78d9 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -155,7 +155,7 @@ namespace MWRender if (const osg::Sequence* sq = dynamic_cast(node)) { osg::Group* n = new osg::Group; - n->addChild(operator()(sq->getChild(sq->getValue()))); + n->addChild(operator()(sq->getChild(sq->getValue() != -1 ? sq->getValue() : 0))); n->setDataVariance(osg::Object::STATIC); return n; } @@ -310,7 +310,7 @@ namespace MWRender } if (osg::Sequence* sq = dynamic_cast(&node)) { - traverse(*sq->getChild(sq->getValue())); + traverse(*sq->getChild(sq->getValue() != -1 ? sq->getValue() : 0)); return; } From 373776170dc749cce60c21918138eeceecd87f70 Mon Sep 17 00:00:00 2001 From: Wolfgang Lieff Date: Thu, 7 Apr 2022 00:49:08 +0200 Subject: [PATCH 5/5] refactor for NiFltAnimationNode --- components/nif/node.hpp | 6 +++--- components/nifosg/nifloader.cpp | 34 ++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 2f64e39a75..b63fc03804 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -433,17 +433,17 @@ struct NiLODNode : public NiSwitchNode struct NiFltAnimationNode : public NiSwitchNode { - float mInterval; + float mDuration; enum Flags { - Flag_Reverse = 0x40 + Flag_Swing = 0x40 }; void read(NIFStream *nif) override { NiSwitchNode::read(nif); - mInterval = nif->getFloat(); + mDuration = nif->getFloat(); } }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 9cd2685747..403fc8fef8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -417,19 +417,33 @@ namespace NifOsg return switchNode; } - static osg::ref_ptr handleSequenceNode(const Nif::NiFltAnimationNode* niFltAnimationNode) + static osg::ref_ptr prepareSequenceNode(const Nif::Node* nifNode) { + const Nif::NiFltAnimationNode* niFltAnimationNode = static_cast(nifNode); osg::ref_ptr sequenceNode (new osg::Sequence); sequenceNode->setName(niFltAnimationNode->name); - sequenceNode->setDefaultTime(niFltAnimationNode->mInterval); - sequenceNode->setMode(osg::Sequence::START); - if (niFltAnimationNode->flags & Nif::NiFltAnimationNode::Flag_Reverse) - sequenceNode->setDuration(0.2f, -1); - else - sequenceNode->setDuration(-0.2f, -1); + if (niFltAnimationNode->children.length()!=0) + { + if (niFltAnimationNode->flags & Nif::NiFltAnimationNode::Flag_Swing) + sequenceNode->setDefaultTime(niFltAnimationNode->mDuration/(niFltAnimationNode->children.length()*2)); + else + sequenceNode->setDefaultTime(niFltAnimationNode->mDuration/niFltAnimationNode->children.length()); + } return sequenceNode; } + static void activateSequenceNode(osg::Group* osgNode, const Nif::Node* nifNode) + { + const Nif::NiFltAnimationNode* niFltAnimationNode = static_cast(nifNode); + osg::Sequence* sequenceNode = static_cast(osgNode); + if (niFltAnimationNode->flags & Nif::NiFltAnimationNode::Flag_Swing) + sequenceNode->setInterval(osg::Sequence::SWING, 0,-1); + else + sequenceNode->setInterval(osg::Sequence::LOOP, 0,-1); + sequenceNode->setDuration(1.0f, -1); + sequenceNode->setMode(osg::Sequence::START); + } + osg::ref_ptr handleSourceTexture(const Nif::NiSourceTexture* st, Resource::ImageManager* imageManager) { if (!st) @@ -727,8 +741,7 @@ namespace NifOsg } else if (nifNode->recType == Nif::RC_NiFltAnimationNode) { - const Nif::NiFltAnimationNode* niFltAnimationNode = static_cast(nifNode); - osg::ref_ptr sequenceNode = handleSequenceNode(niFltAnimationNode); + osg::ref_ptr sequenceNode = prepareSequenceNode(nifNode); node->addChild(sequenceNode); currentNode = sequenceNode; } @@ -752,6 +765,9 @@ namespace NifOsg } } + if (nifNode->recType == Nif::RC_NiFltAnimationNode) + activateSequenceNode(currentNode,nifNode); + return node; }