1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 22:53:50 +00:00

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
nifloader controller particle userdata
nifloader controller particle matrixtransform
)
add_component_dir (nifbullet

View file

@ -4,14 +4,13 @@
#include <osg/TexMat>
#include <osg/Material>
#include <osg/Texture2D>
#include <osg/UserDataContainer>
#include <osgParticle/Emitter>
#include <components/nif/data.hpp>
#include <components/sceneutil/morphgeometry.hpp>
#include "userdata.hpp"
#include "matrixtransform.hpp"
namespace NifOsg
{
@ -119,50 +118,24 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv)
{
if (hasInput())
{
osg::MatrixTransform* trans = static_cast<osg::MatrixTransform*>(node);
osg::Matrix mat = trans->getMatrix();
NifOsg::MatrixTransform* trans = static_cast<NifOsg::MatrixTransform*>(node);
float time = getInputValue(nv);
NodeUserData* userdata = static_cast<NodeUserData*>(trans->getUserDataContainer()->getUserObject(0));
Nif::Matrix3& rot = userdata->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 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
}
trans->updateRotation(getXYZRotation(time));
else // no rotation specified, use the previous value
trans->applyCurrentRotation();
if (setRot) // copy the new values back to the UserData
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 = userdata->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);

View file

@ -9,11 +9,9 @@
#include <components/sceneutil/controller.hpp>
#include <components/sceneutil/statesetupdater.hpp>
#include <set> //UVController
#include <set>
// FlipController
#include <osg/Texture2D>
#include <osg/ref_ptr>
#include <osg/StateSet>
#include <osg/NodeCallback>
@ -22,8 +20,6 @@
namespace osg
{
class Node;
class StateSet;
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 <osg/Matrixf>
#include <osg/MatrixTransform>
#include <osg/Geometry>
#include <osg/Array>
#include <osg/LOD>
@ -43,8 +42,9 @@
#include <components/sceneutil/riggeometry.hpp>
#include <components/sceneutil/morphgeometry.hpp>
#include "matrixtransform.hpp"
#include "nodeindexholder.hpp"
#include "particle.hpp"
#include "userdata.hpp"
namespace
{
@ -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
@ -521,7 +488,14 @@ namespace NifOsg
break;
}
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);
@ -549,14 +523,11 @@ namespace NifOsg
if (!rootNode)
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
// - 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));
node->getOrCreateUserDataContainer()->addUserObject(new NodeIndexHolder(nifNode->recIndex));
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/data.hpp>
#include "userdata.hpp"
#include "nodeindexholder.hpp"
namespace NifOsg
{
@ -383,8 +383,8 @@ void FindGroupByRecIndex::applyNode(osg::Node &searchNode)
{
if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects())
{
NodeUserData* holder = dynamic_cast<NodeUserData*>(searchNode.getUserDataContainer()->getUserObject(0));
if (holder && holder->mIndex == mRecIndex)
NodeIndexHolder* holder = dynamic_cast<NodeIndexHolder*>(searchNode.getUserDataContainer()->getUserObject(0));
if (holder && holder->getIndex() == mRecIndex)
{
osg::Group* group = searchNode.asGroup();
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)
{
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);

View file

@ -6,8 +6,6 @@
#include <osgParticle/ParticleSystemUpdater>
#include <osgParticle/Emitter>
#include <components/nifosg/userdata.hpp>
#include <components/sceneutil/morphgeometry.hpp>
#include <components/sceneutil/riggeometry.hpp>
@ -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<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
{
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::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

View file

@ -3,6 +3,8 @@
#include <osgDB/ObjectWrapper>
#include <osgDB/Registry>
#include <components/nifosg/matrixtransform.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/skeleton.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)
{
return new osgDB::ObjectWrapper(createInstanceFunc<osg::DummyObject>, classname, "osg::Object");
@ -100,6 +111,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 +130,6 @@ void registerSerializers()
"SceneUtil::StateSetUpdater",
"SceneUtil::DisableLight",
"SceneUtil::MWShadowTechnique",
"NifOsg::NodeUserData",
"NifOsg::FlipController",
"NifOsg::KeyframeController",
"NifOsg::TextKeyMapHolder",
@ -131,7 +142,8 @@ void registerSerializers()
"NifOsg::StaticBoundingBoxCallback",
"NifOsg::GeomMorpherController",
"NifOsg::UpdateMorphGeometry",
"NifOsg::CollisionSwitch",
"NifOsg::UVController",
"NifOsg::NodeIndexHolder",
"osgMyGUI::Drawable",
"osg::DrawCallback",
"osgOQ::ClearQueriesCallback",