From 4c9cefefdd707bb2c0c41998dbf69a9dfb3d69a0 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 30 Jun 2020 21:53:59 +0300 Subject: [PATCH 1/7] Get rid of NifOsg::CollisionSwitch --- components/nifosg/nifloader.cpp | 40 ++++++------------------------ components/sceneutil/serialize.cpp | 1 - 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 8266b5e016..04aa91a1fe 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -170,31 +170,6 @@ namespace namespace NifOsg { - class CollisionSwitch : public osg::MatrixTransform - { - public: - CollisionSwitch() : osg::MatrixTransform() - { - } - - CollisionSwitch(const CollisionSwitch& copy, const osg::CopyOp& copyop) - : osg::MatrixTransform(copy, copyop) - { - } - - META_Node(NifOsg, CollisionSwitch) - - CollisionSwitch(const osg::Matrixf& transformations, bool enabled) : osg::MatrixTransform(transformations) - { - setEnabled(enabled); - } - - void setEnabled(bool enabled) - { - setNodeMask(enabled ? ~0 : Loader::getIntersectionDisabledNodeMask()); - } - }; - bool Loader::sShowMarkers = false; void Loader::setShowMarkers(bool show) @@ -501,14 +476,6 @@ namespace NifOsg case Nif::RC_NiBillboardNode: dataVariance = osg::Object::DYNAMIC; break; - case Nif::RC_NiCollisionSwitch: - { - bool enabled = nifNode->flags & Nif::NiNode::Flag_ActiveCollision; - node = new CollisionSwitch(nifNode->trafo.toMatrix(), enabled); - // This matrix transform must not be combined with another matrix transform. - dataVariance = osg::Object::DYNAMIC; - break; - } default: // The Root node can be created as a Group if no transformation is required. // This takes advantage of the fact root nodes can't have additional controllers @@ -523,6 +490,13 @@ namespace NifOsg if (!node) node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); + if (nifNode->recType == Nif::RC_NiCollisionSwitch && !(nifNode->flags & Nif::NiNode::Flag_ActiveCollision)) + { + node->setNodeMask(Loader::getIntersectionDisabledNodeMask()); + // This node must not be combined with another node. + dataVariance = osg::Object::DYNAMIC; + } + node->setDataVariance(dataVariance); return node; diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 60f096a724..f84a19876c 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -131,7 +131,6 @@ void registerSerializers() "NifOsg::StaticBoundingBoxCallback", "NifOsg::GeomMorpherController", "NifOsg::UpdateMorphGeometry", - "NifOsg::CollisionSwitch", "osgMyGUI::Drawable", "osg::DrawCallback", "osgOQ::ClearQueriesCallback", From a61267f57d8c2a4ca7341f127d6f0017a0692455 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 30 Jun 2020 23:27:46 +0300 Subject: [PATCH 2/7] Replace NodeUserData with a custom transform node --- components/CMakeLists.txt | 2 +- components/nifosg/controller.cpp | 14 ++++---- components/nifosg/controller.hpp | 6 +--- components/nifosg/matrixtransform.cpp | 20 +++++++++++ components/nifosg/matrixtransform.hpp | 34 +++++++++++++++++++ components/nifosg/nifloader.cpp | 14 ++------ components/nifosg/particle.cpp | 13 +++----- components/nifosg/userdata.hpp | 48 --------------------------- components/sceneutil/clone.cpp | 11 ------ components/sceneutil/clone.hpp | 2 -- components/sceneutil/serialize.cpp | 12 ++++++- 11 files changed, 79 insertions(+), 97 deletions(-) create mode 100644 components/nifosg/matrixtransform.cpp create mode 100644 components/nifosg/matrixtransform.hpp delete mode 100644 components/nifosg/userdata.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 86d657792e..4627ea2f09 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -59,7 +59,7 @@ add_component_dir (nif ) add_component_dir (nifosg - nifloader controller particle userdata + nifloader controller particle matrixtransform ) add_component_dir (nifbullet diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 3c95394a68..a4db2cba3e 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -4,14 +4,13 @@ #include #include #include -#include #include #include #include -#include "userdata.hpp" +#include "matrixtransform.hpp" namespace NifOsg { @@ -119,13 +118,12 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { - osg::MatrixTransform* trans = static_cast(node); + NifOsg::MatrixTransform* trans = static_cast(node); osg::Matrix mat = trans->getMatrix(); float time = getInputValue(nv); - NodeUserData* userdata = static_cast(trans->getUserDataContainer()->getUserObject(0)); - Nif::Matrix3& rot = userdata->mRotationScale; + Nif::Matrix3& rot = trans->mRotationScale; bool setRot = false; if(!mRotations.empty()) @@ -140,18 +138,18 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) } else { - // no rotation specified, use the previous value from the UserData + // no rotation specified, use the previous value for (int i=0;i<3;++i) for (int j=0;j<3;++j) mat(j,i) = rot.mValues[i][j]; // NB column/row major difference } - if (setRot) // copy the new values back to the UserData + if (setRot) // copy the new values back for (int i=0;i<3;++i) for (int j=0;j<3;++j) rot.mValues[i][j] = mat(j,i); // NB column/row major difference - float& scale = userdata->mScale; + float& scale = trans->mScale; if(!mScales.empty()) scale = mScales.interpKey(time); diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index c81f97a714..df1086f56f 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -9,11 +9,9 @@ #include #include -#include //UVController +#include -// FlipController #include -#include #include #include @@ -22,8 +20,6 @@ namespace osg { - class Node; - class StateSet; class Material; } diff --git a/components/nifosg/matrixtransform.cpp b/components/nifosg/matrixtransform.cpp new file mode 100644 index 0000000000..96450313de --- /dev/null +++ b/components/nifosg/matrixtransform.cpp @@ -0,0 +1,20 @@ +#include "matrixtransform.hpp" + +namespace NifOsg +{ + MatrixTransform::MatrixTransform(int recordIndex, const Nif::Transformation &trafo) + : osg::MatrixTransform(trafo.toMatrix()) + , mIndex(recordIndex) + , mScale(trafo.scale) + , mRotationScale(trafo.rotation) + { + } + + MatrixTransform::MatrixTransform(const MatrixTransform ©, const osg::CopyOp ©op) + : osg::MatrixTransform(copy, copyop) + , mIndex(copy.mIndex) + , mScale(copy.mScale) + , mRotationScale(copy.mRotationScale) + { + } +} diff --git a/components/nifosg/matrixtransform.hpp b/components/nifosg/matrixtransform.hpp new file mode 100644 index 0000000000..61d2438dee --- /dev/null +++ b/components/nifosg/matrixtransform.hpp @@ -0,0 +1,34 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_MATRIXTRANSFORM_H +#define OPENMW_COMPONENTS_NIFOSG_MATRIXTRANSFORM_H + +#include + +#include + +namespace NifOsg +{ + + class MatrixTransform : public osg::MatrixTransform + { + public: + using osg::MatrixTransform::MatrixTransform; + MatrixTransform(int recordIndex, const Nif::Transformation &trafo); + MatrixTransform(const MatrixTransform ©, const osg::CopyOp ©op); + + META_Node(NifOsg, MatrixTransform) + + // NIF record index + int mIndex{0}; + + // Hack: account for Transform differences between OSG and NIFs. + // OSG uses a 4x4 matrix, NIF's use a 3x3 rotationScale, float scale, and vec3 position. + // Decomposing the original components from the 4x4 matrix isn't possible, which causes + // problems when a KeyframeController wants to change only one of these components. So + // we store the scale and rotation components separately here. + float mScale{0.f}; + Nif::Matrix3 mRotationScale; + }; + +} + +#endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 04aa91a1fe..68e3f9a9ce 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -43,8 +42,8 @@ #include #include +#include "matrixtransform.hpp" #include "particle.hpp" -#include "userdata.hpp" namespace { @@ -488,7 +487,7 @@ namespace NifOsg break; } if (!node) - node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); + node = new NifOsg::MatrixTransform(nifNode->recIndex, nifNode->trafo); if (nifNode->recType == Nif::RC_NiCollisionSwitch && !(nifNode->flags & Nif::NiNode::Flag_ActiveCollision)) { @@ -523,15 +522,6 @@ namespace NifOsg if (!rootNode) rootNode = node; - // UserData used for a variety of features: - // - finding the correct emitter node for a particle system - // - establishing connections to the animated collision shapes, which are handled in a separate loader - // - finding a random child NiNode in NiBspArrayController - // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to - // change only certain elements of the 4x4 transform - node->getOrCreateUserDataContainer()->addUserObject( - new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation)); - for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->next) { if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index f71dcdd967..7c72771186 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -11,7 +11,7 @@ #include #include -#include "userdata.hpp" +#include "matrixtransform.hpp" namespace NifOsg { @@ -381,16 +381,11 @@ void FindGroupByRecIndex::apply(osg::Geometry &node) void FindGroupByRecIndex::applyNode(osg::Node &searchNode) { - if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects()) + if (NifOsg::MatrixTransform* trans = dynamic_cast(&searchNode)) { - NodeUserData* holder = dynamic_cast(searchNode.getUserDataContainer()->getUserObject(0)); - if (holder && holder->mIndex == mRecIndex) + if (trans->mIndex == mRecIndex) { - osg::Group* group = searchNode.asGroup(); - if (!group) - group = searchNode.getParent(0); - - mFound = group; + mFound = trans; mFoundPath = getNodePath(); return; } diff --git a/components/nifosg/userdata.hpp b/components/nifosg/userdata.hpp deleted file mode 100644 index 42fcaff471..0000000000 --- a/components/nifosg/userdata.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef OPENMW_COMPONENTS_NIFOSG_USERDATA_H -#define OPENMW_COMPONENTS_NIFOSG_USERDATA_H - -#include - -#include - -namespace NifOsg -{ - - // Note if you are copying a scene graph with this user data you should use the DEEP_COPY_USERDATA copyop. - class NodeUserData : public osg::Object - { - public: - NodeUserData(int index, float scale, const Nif::Matrix3& rotationScale) - : mIndex(index), mScale(scale), mRotationScale(rotationScale) - { - } - NodeUserData() - : mIndex(0), mScale(0) - { - } - NodeUserData(const NodeUserData& copy, const osg::CopyOp& copyop) - : Object(copy, copyop) - , mIndex(copy.mIndex) - , mScale(copy.mScale) - , mRotationScale(copy.mRotationScale) - { - } - - META_Object(NifOsg, NodeUserData) - - // NIF record index - int mIndex; - - // Hack: account for Transform differences between OSG and NIFs. - // OSG uses a 4x4 matrix, NIF's use a 3x3 rotationScale, float scale, and vec3 position. - // Decomposing the original components from the 4x4 matrix isn't possible, which causes - // problems when a KeyframeController wants to change only one of these components. So - // we store the scale and rotation components separately here. - // Note for a cleaner solution it would be possible to write a custom Transform node - float mScale; - Nif::Matrix3 mRotationScale; - }; - -} - -#endif diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index c3261515d6..1de7bfd91e 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include @@ -22,15 +20,6 @@ namespace SceneUtil | osg::CopyOp::DEEP_COPY_USERDATA); } - osg::Object* CopyOp::operator ()(const osg::Object* node) const - { - // We should copy node transformations when we copy node - if (dynamic_cast(node)) - return static_cast(node->clone(*this)); - - return osg::CopyOp::operator()(node); - } - osg::Node* CopyOp::operator ()(const osg::Node* node) const { if (const osgParticle::ParticleProcessor* processor = dynamic_cast(node)) diff --git a/components/sceneutil/clone.hpp b/components/sceneutil/clone.hpp index cf6d79e683..8c5fbd3510 100644 --- a/components/sceneutil/clone.hpp +++ b/components/sceneutil/clone.hpp @@ -30,8 +30,6 @@ namespace SceneUtil virtual osg::Node* operator() (const osg::Node* node) const; virtual osg::Drawable* operator() (const osg::Drawable* drawable) const; - virtual osg::Object* operator ()(const osg::Object* node) const; - private: // maps new pointers to their old pointers // a little messy, but I think this should be the most efficient way diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index f84a19876c..398d9cc0cc 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -1,5 +1,6 @@ #include "serialize.hpp" +#include #include #include @@ -74,6 +75,15 @@ public: } }; +class MatrixTransformSerializer : public osgDB::ObjectWrapper +{ +public: + MatrixTransformSerializer() + : osgDB::ObjectWrapper(createInstanceFunc, "NifOsg::MatrixTransform", "osg::Object osg::Node osg::Transform osg::MatrixTransform NifOsg::MatrixTransform") + { + } +}; + osgDB::ObjectWrapper* makeDummySerializer(const std::string& classname) { return new osgDB::ObjectWrapper(createInstanceFunc, classname, "osg::Object"); @@ -100,6 +110,7 @@ void registerSerializers() mgr->addWrapper(new MorphGeometrySerializer); mgr->addWrapper(new LightManagerSerializer); mgr->addWrapper(new CameraRelativeTransformSerializer); + mgr->addWrapper(new MatrixTransformSerializer); // Don't serialize Geometry data as we are more interested in the overall structure rather than tons of vertex data that would make the file large and hard to read. mgr->removeWrapper(mgr->findWrapper("osg::Geometry")); @@ -118,7 +129,6 @@ void registerSerializers() "SceneUtil::StateSetUpdater", "SceneUtil::DisableLight", "SceneUtil::MWShadowTechnique", - "NifOsg::NodeUserData", "NifOsg::FlipController", "NifOsg::KeyframeController", "NifOsg::TextKeyMapHolder", From 3b55d657e56780160a64f6d08b5446a30cbbe157 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 30 Jun 2020 23:30:22 +0300 Subject: [PATCH 3/7] CopyRigVisitor: Log the number of parents in multiple parents error --- components/sceneutil/attach.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index c438e705d8..2a6ec84e5b 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -64,7 +64,7 @@ namespace SceneUtil for (const osg::ref_ptr& node : mToCopy) { if (node->getNumParents() > 1) - Log(Debug::Error) << "Error CopyRigVisitor: node has multiple parents"; + Log(Debug::Error) << "Error CopyRigVisitor: node has " << node->getNumParents() << " parents"; while (node->getNumParents()) node->getParent(0)->removeChild(node); From cc791af0f5102445bb9a5547a03c8dc4edfe25c0 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 11 Jul 2020 17:55:15 +0300 Subject: [PATCH 4/7] Serialization fixes Make sure NifOsg::MatrixTransform serialization behaves as intended Add a dummy serializer for NifOsg::UVController --- components/sceneutil/serialize.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 398d9cc0cc..1577f080f3 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -1,9 +1,10 @@ #include "serialize.hpp" -#include #include #include +#include + #include #include #include @@ -79,7 +80,7 @@ class MatrixTransformSerializer : public osgDB::ObjectWrapper { public: MatrixTransformSerializer() - : osgDB::ObjectWrapper(createInstanceFunc, "NifOsg::MatrixTransform", "osg::Object osg::Node osg::Transform osg::MatrixTransform NifOsg::MatrixTransform") + : osgDB::ObjectWrapper(createInstanceFunc, "NifOsg::MatrixTransform", "osg::Object osg::Node osg::Transform osg::MatrixTransform NifOsg::MatrixTransform") { } }; @@ -141,6 +142,7 @@ void registerSerializers() "NifOsg::StaticBoundingBoxCallback", "NifOsg::GeomMorpherController", "NifOsg::UpdateMorphGeometry", + "NifOsg::UVController", "osgMyGUI::Drawable", "osg::DrawCallback", "osgOQ::ClearQueriesCallback", From ad87289d59fc84306d67fb7d106e21f672dec905 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 11 Jul 2020 20:15:13 +0300 Subject: [PATCH 5/7] Fix NifOsg::MatrixTransform constructor inheritance --- components/nifosg/matrixtransform.cpp | 5 +++++ components/nifosg/matrixtransform.hpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/nifosg/matrixtransform.cpp b/components/nifosg/matrixtransform.cpp index 96450313de..b61df834b6 100644 --- a/components/nifosg/matrixtransform.cpp +++ b/components/nifosg/matrixtransform.cpp @@ -2,6 +2,11 @@ namespace NifOsg { + MatrixTransform::MatrixTransform() + : osg::MatrixTransform() + { + } + MatrixTransform::MatrixTransform(int recordIndex, const Nif::Transformation &trafo) : osg::MatrixTransform(trafo.toMatrix()) , mIndex(recordIndex) diff --git a/components/nifosg/matrixtransform.hpp b/components/nifosg/matrixtransform.hpp index 61d2438dee..86c9034911 100644 --- a/components/nifosg/matrixtransform.hpp +++ b/components/nifosg/matrixtransform.hpp @@ -11,7 +11,7 @@ namespace NifOsg class MatrixTransform : public osg::MatrixTransform { public: - using osg::MatrixTransform::MatrixTransform; + MatrixTransform(); MatrixTransform(int recordIndex, const Nif::Transformation &trafo); MatrixTransform(const MatrixTransform ©, const osg::CopyOp ©op); From f93655e803d1b611f53477872f41a37eac5a8679 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 11 Jul 2020 20:59:21 +0300 Subject: [PATCH 6/7] Encapsulate NIF transform changes in NifOsg::MatrixTransform --- components/nifosg/controller.cpp | 47 +++++++-------------------- components/nifosg/matrixtransform.cpp | 33 +++++++++++++++++++ components/nifosg/matrixtransform.hpp | 13 ++++++++ 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index a4db2cba3e..203951eddc 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -119,48 +119,23 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) if (hasInput()) { NifOsg::MatrixTransform* trans = static_cast(node); - osg::Matrix mat = trans->getMatrix(); float time = getInputValue(nv); - Nif::Matrix3& rot = trans->mRotationScale; - - bool setRot = false; - if(!mRotations.empty()) - { - mat.setRotate(mRotations.interpKey(time)); - setRot = true; - } + if (!mRotations.empty()) + trans->updateRotation(mRotations.interpKey(time)); else if (!mXRotations.empty() || !mYRotations.empty() || !mZRotations.empty()) - { - mat.setRotate(getXYZRotation(time)); - setRot = true; - } - else - { - // no rotation specified, use the previous value - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - mat(j,i) = rot.mValues[i][j]; // NB column/row major difference - } + trans->updateRotation(getXYZRotation(time)); + else // no rotation specified, use the previous value + trans->applyCurrentRotation(); - if (setRot) // copy the new values back - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - rot.mValues[i][j] = mat(j,i); // NB column/row major difference + if (!mScales.empty()) + trans->updateScale(mScales.interpKey(time)); + else // no scale specified, use the previous value + trans->applyCurrentScale(); - float& scale = trans->mScale; - if(!mScales.empty()) - scale = mScales.interpKey(time); - - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - mat(i,j) *= scale; - - if(!mTranslations.empty()) - mat.setTrans(mTranslations.interpKey(time)); - - trans->setMatrix(mat); + if (!mTranslations.empty()) + trans->setTranslation(mTranslations.interpKey(time)); } traverse(node, nv); diff --git a/components/nifosg/matrixtransform.cpp b/components/nifosg/matrixtransform.cpp index b61df834b6..12144b62a6 100644 --- a/components/nifosg/matrixtransform.cpp +++ b/components/nifosg/matrixtransform.cpp @@ -22,4 +22,37 @@ namespace NifOsg , mRotationScale(copy.mRotationScale) { } + + void MatrixTransform::applyCurrentRotation() + { + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + _matrix(j,i) = mRotationScale.mValues[i][j]; // NB column/row major difference + } + + void MatrixTransform::applyCurrentScale() + { + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + _matrix(i,j) *= mScale; + } + + void MatrixTransform::updateRotation(const osg::Quat& rotation) + { + _matrix.setRotate(rotation); + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + mRotationScale.mValues[i][j] = _matrix(j,i); // NB column/row major difference + } + + void MatrixTransform::updateScale(const float scale) + { + mScale = scale; + applyCurrentScale(); + } + + void MatrixTransform::setTranslation(const osg::Vec3f& translation) + { + _matrix.setTrans(translation); + } } diff --git a/components/nifosg/matrixtransform.hpp b/components/nifosg/matrixtransform.hpp index 86c9034911..b633efaad6 100644 --- a/components/nifosg/matrixtransform.hpp +++ b/components/nifosg/matrixtransform.hpp @@ -17,9 +17,22 @@ namespace NifOsg META_Node(NifOsg, MatrixTransform) + // Apply the current NIF rotation or scale to OSG matrix. + void applyCurrentRotation(); + void applyCurrentScale(); + + // Apply the given rotation to OSG matrix directly and update NIF rotation matrix. + void updateRotation(const osg::Quat& rotation); + // Update current NIF scale and apply it to OSG matrix. + void updateScale(const float scale); + + // Apply the given translation to OSG matrix. + void setTranslation(const osg::Vec3f& translation); + // NIF record index int mIndex{0}; + private: // Hack: account for Transform differences between OSG and NIFs. // OSG uses a 4x4 matrix, NIF's use a 3x3 rotationScale, float scale, and vec3 position. // Decomposing the original components from the 4x4 matrix isn't possible, which causes From 46825e8a4d4c09d293505954ed534f2f02955e69 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 12 Jul 2020 15:34:22 +0300 Subject: [PATCH 7/7] Move NIF record index back to a separate user object This makes sure it's never erroneously optimized out. NodeIndexHolders don't need to be cloned as their record index is never supposed to be changed. --- components/nifosg/matrixtransform.cpp | 4 +-- components/nifosg/matrixtransform.hpp | 5 +--- components/nifosg/nifloader.cpp | 9 ++++++- components/nifosg/nodeindexholder.hpp | 35 +++++++++++++++++++++++++++ components/nifosg/particle.cpp | 13 +++++++--- components/sceneutil/serialize.cpp | 1 + 6 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 components/nifosg/nodeindexholder.hpp diff --git a/components/nifosg/matrixtransform.cpp b/components/nifosg/matrixtransform.cpp index 12144b62a6..72e12ecf8e 100644 --- a/components/nifosg/matrixtransform.cpp +++ b/components/nifosg/matrixtransform.cpp @@ -7,9 +7,8 @@ namespace NifOsg { } - MatrixTransform::MatrixTransform(int recordIndex, const Nif::Transformation &trafo) + MatrixTransform::MatrixTransform(const Nif::Transformation &trafo) : osg::MatrixTransform(trafo.toMatrix()) - , mIndex(recordIndex) , mScale(trafo.scale) , mRotationScale(trafo.rotation) { @@ -17,7 +16,6 @@ namespace NifOsg MatrixTransform::MatrixTransform(const MatrixTransform ©, const osg::CopyOp ©op) : osg::MatrixTransform(copy, copyop) - , mIndex(copy.mIndex) , mScale(copy.mScale) , mRotationScale(copy.mRotationScale) { diff --git a/components/nifosg/matrixtransform.hpp b/components/nifosg/matrixtransform.hpp index b633efaad6..ac2fbb57a6 100644 --- a/components/nifosg/matrixtransform.hpp +++ b/components/nifosg/matrixtransform.hpp @@ -12,7 +12,7 @@ namespace NifOsg { public: MatrixTransform(); - MatrixTransform(int recordIndex, const Nif::Transformation &trafo); + MatrixTransform(const Nif::Transformation &trafo); MatrixTransform(const MatrixTransform ©, const osg::CopyOp ©op); META_Node(NifOsg, MatrixTransform) @@ -29,9 +29,6 @@ namespace NifOsg // Apply the given translation to OSG matrix. void setTranslation(const osg::Vec3f& translation); - // NIF record index - int mIndex{0}; - private: // Hack: account for Transform differences between OSG and NIFs. // OSG uses a 4x4 matrix, NIF's use a 3x3 rotationScale, float scale, and vec3 position. diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 68e3f9a9ce..f88800e364 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -43,6 +43,7 @@ #include #include "matrixtransform.hpp" +#include "nodeindexholder.hpp" #include "particle.hpp" namespace @@ -487,7 +488,7 @@ namespace NifOsg break; } if (!node) - node = new NifOsg::MatrixTransform(nifNode->recIndex, nifNode->trafo); + node = new NifOsg::MatrixTransform(nifNode->trafo); if (nifNode->recType == Nif::RC_NiCollisionSwitch && !(nifNode->flags & Nif::NiNode::Flag_ActiveCollision)) { @@ -522,6 +523,12 @@ namespace NifOsg if (!rootNode) rootNode = node; + // The original NIF record index is used for a variety of features: + // - finding the correct emitter node for a particle system + // - establishing connections to the animated collision shapes, which are handled in a separate loader + // - finding a random child NiNode in NiBspArrayController + node->getOrCreateUserDataContainer()->addUserObject(new NodeIndexHolder(nifNode->recIndex)); + for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->next) { if(e->recType == Nif::RC_NiTextKeyExtraData && textKeys) diff --git a/components/nifosg/nodeindexholder.hpp b/components/nifosg/nodeindexholder.hpp new file mode 100644 index 0000000000..e7d4f0db31 --- /dev/null +++ b/components/nifosg/nodeindexholder.hpp @@ -0,0 +1,35 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_NODEINDEXHOLDER_H +#define OPENMW_COMPONENTS_NIFOSG_NODEINDEXHOLDER_H + +#include + +namespace NifOsg +{ + + class NodeIndexHolder : public osg::Object + { + public: + NodeIndexHolder() = default; + NodeIndexHolder(int index) + : mIndex(index) + { + } + NodeIndexHolder(const NodeIndexHolder& copy, const osg::CopyOp& copyop) + : Object(copy, copyop) + , mIndex(copy.mIndex) + { + } + + META_Object(NifOsg, NodeIndexHolder) + + int getIndex() const { return mIndex; } + + private: + + // NIF record index + int mIndex{0}; + }; + +} + +#endif diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 7c72771186..0cbc3f22b5 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -11,7 +11,7 @@ #include #include -#include "matrixtransform.hpp" +#include "nodeindexholder.hpp" namespace NifOsg { @@ -381,11 +381,16 @@ void FindGroupByRecIndex::apply(osg::Geometry &node) void FindGroupByRecIndex::applyNode(osg::Node &searchNode) { - if (NifOsg::MatrixTransform* trans = dynamic_cast(&searchNode)) + if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects()) { - if (trans->mIndex == mRecIndex) + NodeIndexHolder* holder = dynamic_cast(searchNode.getUserDataContainer()->getUserObject(0)); + if (holder && holder->getIndex() == mRecIndex) { - mFound = trans; + osg::Group* group = searchNode.asGroup(); + if (!group) + group = searchNode.getParent(0); + + mFound = group; mFoundPath = getNodePath(); return; } diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 1577f080f3..62325186c0 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -143,6 +143,7 @@ void registerSerializers() "NifOsg::GeomMorpherController", "NifOsg::UpdateMorphGeometry", "NifOsg::UVController", + "NifOsg::NodeIndexHolder", "osgMyGUI::Drawable", "osg::DrawCallback", "osgOQ::ClearQueriesCallback",