Merge pull request #2962 from Capostrophic/nifcleanup

More NIF-related cleanup
This commit is contained in:
Bret Curtis 2020-07-27 01:28:39 +02:00 committed by GitHub
commit e0655841e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 180 additions and 154 deletions

View File

@ -59,7 +59,7 @@ add_component_dir (nif
) )
add_component_dir (nifosg add_component_dir (nifosg
nifloader controller particle userdata nifloader controller particle matrixtransform
) )
add_component_dir (nifbullet add_component_dir (nifbullet

View File

@ -4,14 +4,13 @@
#include <osg/TexMat> #include <osg/TexMat>
#include <osg/Material> #include <osg/Material>
#include <osg/Texture2D> #include <osg/Texture2D>
#include <osg/UserDataContainer>
#include <osgParticle/Emitter> #include <osgParticle/Emitter>
#include <components/nif/data.hpp> #include <components/nif/data.hpp>
#include <components/sceneutil/morphgeometry.hpp> #include <components/sceneutil/morphgeometry.hpp>
#include "userdata.hpp" #include "matrixtransform.hpp"
namespace NifOsg namespace NifOsg
{ {
@ -119,50 +118,24 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv)
{ {
if (hasInput()) if (hasInput())
{ {
osg::MatrixTransform* trans = static_cast<osg::MatrixTransform*>(node); NifOsg::MatrixTransform* trans = static_cast<NifOsg::MatrixTransform*>(node);
osg::Matrix mat = trans->getMatrix();
float time = getInputValue(nv); float time = getInputValue(nv);
NodeUserData* userdata = static_cast<NodeUserData*>(trans->getUserDataContainer()->getUserObject(0)); if (!mRotations.empty())
Nif::Matrix3& rot = userdata->mRotationScale; trans->updateRotation(mRotations.interpKey(time));
bool setRot = false;
if(!mRotations.empty())
{
mat.setRotate(mRotations.interpKey(time));
setRot = true;
}
else if (!mXRotations.empty() || !mYRotations.empty() || !mZRotations.empty()) else if (!mXRotations.empty() || !mYRotations.empty() || !mZRotations.empty())
{ trans->updateRotation(getXYZRotation(time));
mat.setRotate(getXYZRotation(time)); else // no rotation specified, use the previous value
setRot = true; trans->applyCurrentRotation();
}
else
{
// no rotation specified, use the previous value from the UserData
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 (!mScales.empty())
for (int i=0;i<3;++i) trans->updateScale(mScales.interpKey(time));
for (int j=0;j<3;++j) else // no scale specified, use the previous value
rot.mValues[i][j] = mat(j,i); // NB column/row major difference trans->applyCurrentScale();
float& scale = userdata->mScale; if (!mTranslations.empty())
if(!mScales.empty()) trans->setTranslation(mTranslations.interpKey(time));
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);
} }
traverse(node, nv); traverse(node, nv);

View File

@ -9,11 +9,9 @@
#include <components/sceneutil/controller.hpp> #include <components/sceneutil/controller.hpp>
#include <components/sceneutil/statesetupdater.hpp> #include <components/sceneutil/statesetupdater.hpp>
#include <set> //UVController #include <set>
// FlipController
#include <osg/Texture2D> #include <osg/Texture2D>
#include <osg/ref_ptr>
#include <osg/StateSet> #include <osg/StateSet>
#include <osg/NodeCallback> #include <osg/NodeCallback>
@ -22,8 +20,6 @@
namespace osg namespace osg
{ {
class Node;
class StateSet;
class Material; class Material;
} }

View File

@ -0,0 +1,56 @@
#include "matrixtransform.hpp"
namespace NifOsg
{
MatrixTransform::MatrixTransform()
: osg::MatrixTransform()
{
}
MatrixTransform::MatrixTransform(const Nif::Transformation &trafo)
: osg::MatrixTransform(trafo.toMatrix())
, mScale(trafo.scale)
, mRotationScale(trafo.rotation)
{
}
MatrixTransform::MatrixTransform(const MatrixTransform &copy, const osg::CopyOp &copyop)
: osg::MatrixTransform(copy, copyop)
, mScale(copy.mScale)
, 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);
}
}

View File

@ -0,0 +1,44 @@
#ifndef OPENMW_COMPONENTS_NIFOSG_MATRIXTRANSFORM_H
#define OPENMW_COMPONENTS_NIFOSG_MATRIXTRANSFORM_H
#include <components/nif/niftypes.hpp>
#include <osg/MatrixTransform>
namespace NifOsg
{
class MatrixTransform : public osg::MatrixTransform
{
public:
MatrixTransform();
MatrixTransform(const Nif::Transformation &trafo);
MatrixTransform(const MatrixTransform &copy, const osg::CopyOp &copyop);
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);
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
// 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

View File

@ -3,7 +3,6 @@
#include <mutex> #include <mutex>
#include <osg/Matrixf> #include <osg/Matrixf>
#include <osg/MatrixTransform>
#include <osg/Geometry> #include <osg/Geometry>
#include <osg/Array> #include <osg/Array>
#include <osg/LOD> #include <osg/LOD>
@ -43,8 +42,9 @@
#include <components/sceneutil/riggeometry.hpp> #include <components/sceneutil/riggeometry.hpp>
#include <components/sceneutil/morphgeometry.hpp> #include <components/sceneutil/morphgeometry.hpp>
#include "matrixtransform.hpp"
#include "nodeindexholder.hpp"
#include "particle.hpp" #include "particle.hpp"
#include "userdata.hpp"
namespace namespace
{ {
@ -170,31 +170,6 @@ namespace
namespace NifOsg 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; bool Loader::sShowMarkers = false;
void Loader::setShowMarkers(bool show) void Loader::setShowMarkers(bool show)
@ -501,14 +476,6 @@ namespace NifOsg
case Nif::RC_NiBillboardNode: case Nif::RC_NiBillboardNode:
dataVariance = osg::Object::DYNAMIC; dataVariance = osg::Object::DYNAMIC;
break; 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: default:
// The Root node can be created as a Group if no transformation is required. // 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 // This takes advantage of the fact root nodes can't have additional controllers
@ -521,7 +488,14 @@ namespace NifOsg
break; break;
} }
if (!node) if (!node)
node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); node = new NifOsg::MatrixTransform(nifNode->trafo);
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); node->setDataVariance(dataVariance);
@ -549,14 +523,11 @@ namespace NifOsg
if (!rootNode) if (!rootNode)
rootNode = node; rootNode = node;
// UserData used for a variety of features: // The original NIF record index is used for a variety of features:
// - finding the correct emitter node for a particle system // - finding the correct emitter node for a particle system
// - establishing connections to the animated collision shapes, which are handled in a separate loader // - establishing connections to the animated collision shapes, which are handled in a separate loader
// - finding a random child NiNode in NiBspArrayController // - finding a random child NiNode in NiBspArrayController
// - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to node->getOrCreateUserDataContainer()->addUserObject(new NodeIndexHolder(nifNode->recIndex));
// 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) for (Nif::ExtraPtr e = nifNode->extra; !e.empty(); e = e->next)
{ {

View File

@ -0,0 +1,35 @@
#ifndef OPENMW_COMPONENTS_NIFOSG_NODEINDEXHOLDER_H
#define OPENMW_COMPONENTS_NIFOSG_NODEINDEXHOLDER_H
#include <osg/Object>
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

View File

@ -11,7 +11,7 @@
#include <components/nif/controlled.hpp> #include <components/nif/controlled.hpp>
#include <components/nif/data.hpp> #include <components/nif/data.hpp>
#include "userdata.hpp" #include "nodeindexholder.hpp"
namespace NifOsg namespace NifOsg
{ {
@ -383,8 +383,8 @@ void FindGroupByRecIndex::applyNode(osg::Node &searchNode)
{ {
if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects()) if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects())
{ {
NodeUserData* holder = dynamic_cast<NodeUserData*>(searchNode.getUserDataContainer()->getUserObject(0)); NodeIndexHolder* holder = dynamic_cast<NodeIndexHolder*>(searchNode.getUserDataContainer()->getUserObject(0));
if (holder && holder->mIndex == mRecIndex) if (holder && holder->getIndex() == mRecIndex)
{ {
osg::Group* group = searchNode.asGroup(); osg::Group* group = searchNode.asGroup();
if (!group) if (!group)

View File

@ -1,48 +0,0 @@
#ifndef OPENMW_COMPONENTS_NIFOSG_USERDATA_H
#define OPENMW_COMPONENTS_NIFOSG_USERDATA_H
#include <components/nif/niftypes.hpp>
#include <osg/Object>
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

View File

@ -64,7 +64,7 @@ namespace SceneUtil
for (const osg::ref_ptr<osg::Node>& node : mToCopy) for (const osg::ref_ptr<osg::Node>& node : mToCopy)
{ {
if (node->getNumParents() > 1) 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()) while (node->getNumParents())
node->getParent(0)->removeChild(node); node->getParent(0)->removeChild(node);

View File

@ -6,8 +6,6 @@
#include <osgParticle/ParticleSystemUpdater> #include <osgParticle/ParticleSystemUpdater>
#include <osgParticle/Emitter> #include <osgParticle/Emitter>
#include <components/nifosg/userdata.hpp>
#include <components/sceneutil/morphgeometry.hpp> #include <components/sceneutil/morphgeometry.hpp>
#include <components/sceneutil/riggeometry.hpp> #include <components/sceneutil/riggeometry.hpp>
@ -22,15 +20,6 @@ namespace SceneUtil
| osg::CopyOp::DEEP_COPY_USERDATA); | 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<const NifOsg::NodeUserData*>(node))
return static_cast<NifOsg::NodeUserData*>(node->clone(*this));
return osg::CopyOp::operator()(node);
}
osg::Node* CopyOp::operator ()(const osg::Node* node) const osg::Node* CopyOp::operator ()(const osg::Node* node) const
{ {
if (const osgParticle::ParticleProcessor* processor = dynamic_cast<const osgParticle::ParticleProcessor*>(node)) if (const osgParticle::ParticleProcessor* processor = dynamic_cast<const osgParticle::ParticleProcessor*>(node))

View File

@ -30,8 +30,6 @@ namespace SceneUtil
virtual osg::Node* operator() (const osg::Node* node) const; virtual osg::Node* operator() (const osg::Node* node) const;
virtual osg::Drawable* operator() (const osg::Drawable* drawable) const; virtual osg::Drawable* operator() (const osg::Drawable* drawable) const;
virtual osg::Object* operator ()(const osg::Object* node) const;
private: private:
// maps new pointers to their old pointers // maps new pointers to their old pointers
// a little messy, but I think this should be the most efficient way // a little messy, but I think this should be the most efficient way

View File

@ -3,6 +3,8 @@
#include <osgDB/ObjectWrapper> #include <osgDB/ObjectWrapper>
#include <osgDB/Registry> #include <osgDB/Registry>
#include <components/nifosg/matrixtransform.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/skeleton.hpp> #include <components/sceneutil/skeleton.hpp>
#include <components/sceneutil/riggeometry.hpp> #include <components/sceneutil/riggeometry.hpp>
@ -74,6 +76,15 @@ public:
} }
}; };
class MatrixTransformSerializer : public osgDB::ObjectWrapper
{
public:
MatrixTransformSerializer()
: osgDB::ObjectWrapper(createInstanceFunc<NifOsg::MatrixTransform>, "NifOsg::MatrixTransform", "osg::Object osg::Node osg::Transform osg::MatrixTransform NifOsg::MatrixTransform")
{
}
};
osgDB::ObjectWrapper* makeDummySerializer(const std::string& classname) osgDB::ObjectWrapper* makeDummySerializer(const std::string& classname)
{ {
return new osgDB::ObjectWrapper(createInstanceFunc<osg::DummyObject>, classname, "osg::Object"); return new osgDB::ObjectWrapper(createInstanceFunc<osg::DummyObject>, classname, "osg::Object");
@ -100,6 +111,7 @@ void registerSerializers()
mgr->addWrapper(new MorphGeometrySerializer); mgr->addWrapper(new MorphGeometrySerializer);
mgr->addWrapper(new LightManagerSerializer); mgr->addWrapper(new LightManagerSerializer);
mgr->addWrapper(new CameraRelativeTransformSerializer); 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. // 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")); mgr->removeWrapper(mgr->findWrapper("osg::Geometry"));
@ -118,7 +130,6 @@ void registerSerializers()
"SceneUtil::StateSetUpdater", "SceneUtil::StateSetUpdater",
"SceneUtil::DisableLight", "SceneUtil::DisableLight",
"SceneUtil::MWShadowTechnique", "SceneUtil::MWShadowTechnique",
"NifOsg::NodeUserData",
"NifOsg::FlipController", "NifOsg::FlipController",
"NifOsg::KeyframeController", "NifOsg::KeyframeController",
"NifOsg::TextKeyMapHolder", "NifOsg::TextKeyMapHolder",
@ -131,7 +142,8 @@ void registerSerializers()
"NifOsg::StaticBoundingBoxCallback", "NifOsg::StaticBoundingBoxCallback",
"NifOsg::GeomMorpherController", "NifOsg::GeomMorpherController",
"NifOsg::UpdateMorphGeometry", "NifOsg::UpdateMorphGeometry",
"NifOsg::CollisionSwitch", "NifOsg::UVController",
"NifOsg::NodeIndexHolder",
"osgMyGUI::Drawable", "osgMyGUI::Drawable",
"osg::DrawCallback", "osg::DrawCallback",
"osgOQ::ClearQueriesCallback", "osgOQ::ClearQueriesCallback",