Change rotation/scale workaround in preparation for loading .kf controllers

pull/638/head
scrawl 10 years ago
parent 15f9c1ddcf
commit 2db5df77f0

@ -43,7 +43,7 @@ add_component_dir (nif
) )
add_component_dir (nifosg add_component_dir (nifosg
nifloader controller particle nifloader controller particle userdata
) )
#add_component_dir (nifcache #add_component_dir (nifcache

@ -46,7 +46,7 @@ struct Matrix3
struct Transformation struct Transformation
{ {
osg::Vec3f pos; osg::Vec3f pos;
Matrix3 rotation; Matrix3 rotation; // this can contain scale components too, including negative and nonuniform scales
float scale; float scale;
static const Transformation& getIdentity() static const Transformation& getIdentity()

@ -4,15 +4,17 @@
#include <osg/TexMat> #include <osg/TexMat>
#include <osg/Material> #include <osg/Material>
#include <osg/Texture2D> #include <osg/Texture2D>
#include <osg/io_utils>
#include <osg/UserDataContainer>
#include <osgAnimation/MorphGeometry> #include <osgAnimation/MorphGeometry>
#include <osgParticle/Emitter> #include <osgParticle/Emitter>
#include <osg/io_utils>
#include <components/nif/data.hpp> #include <components/nif/data.hpp>
#include "userdata.hpp"
namespace NifOsg namespace NifOsg
{ {
@ -76,13 +78,10 @@ KeyframeController::KeyframeController(const KeyframeController &copy, const osg
, mTranslations(copy.mTranslations) , mTranslations(copy.mTranslations)
, mScales(copy.mScales) , mScales(copy.mScales)
, mNif(copy.mNif) , mNif(copy.mNif)
, mInitialQuat(copy.mInitialQuat)
, mInitialScale(copy.mInitialScale)
{ {
} }
KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data)
osg::Quat initialQuat, float initialScale)
: mRotations(&data->mRotations) : mRotations(&data->mRotations)
, mXRotations(&data->mXRotations) , mXRotations(&data->mXRotations)
, mYRotations(&data->mYRotations) , mYRotations(&data->mYRotations)
@ -90,9 +89,8 @@ KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::Ni
, mTranslations(&data->mTranslations) , mTranslations(&data->mTranslations)
, mScales(&data->mScales) , mScales(&data->mScales)
, mNif(nif) , mNif(nif)
, mInitialQuat(initialQuat) {
, mInitialScale(initialScale) }
{ }
osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time)
{ {
@ -154,15 +152,35 @@ void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv)
float time = getInputValue(nv); float time = getInputValue(nv);
NodeUserData* userdata = static_cast<NodeUserData*>(trans->getUserDataContainer()->getUserObject(0));
Nif::Matrix3& rot = userdata->mRotationScale;
bool setRot = false;
if(mRotations->mKeys.size() > 0) if(mRotations->mKeys.size() > 0)
{
mat.setRotate(interpKey(mRotations->mKeys, time)); mat.setRotate(interpKey(mRotations->mKeys, time));
setRot = true;
}
else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty())
{
mat.setRotate(getXYZRotation(time)); mat.setRotate(getXYZRotation(time));
setRot = true;
}
else else
mat.setRotate(mInitialQuat); {
// 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
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
// let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...)
float scale = mInitialScale; float& scale = userdata->mScale;
if(mScales->mKeys.size() > 0) if(mScales->mKeys.size() > 0)
scale = interpKey(mScales->mKeys, time); scale = interpKey(mScales->mKeys, time);

@ -147,11 +147,9 @@ namespace NifOsg
const Nif::FloatKeyMap* mZRotations; const Nif::FloatKeyMap* mZRotations;
const Nif::Vector3KeyMap* mTranslations; const Nif::Vector3KeyMap* mTranslations;
const Nif::FloatKeyMap* mScales; const Nif::FloatKeyMap* mScales;
// TODO: we don't need to keep the whole NIF around, just change the key maps to Referenced
Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid
osg::Quat mInitialQuat;
float mInitialScale;
using ValueInterpolator::interpKey; using ValueInterpolator::interpKey;
@ -161,8 +159,7 @@ namespace NifOsg
public: public:
/// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists.
KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data);
osg::Quat initialQuat, float initialScale);
KeyframeController(); KeyframeController();
KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop);

@ -42,6 +42,7 @@
#include <components/nif/node.hpp> #include <components/nif/node.hpp>
#include "particle.hpp" #include "particle.hpp"
#include "userdata.hpp"
namespace namespace
{ {
@ -191,12 +192,13 @@ namespace
{ {
if (_referenceFrame==RELATIVE_RF) if (_referenceFrame==RELATIVE_RF)
{ {
const NifOsg::NodeUserData* userdata = static_cast<const NifOsg::NodeUserData*>(getUserDataContainer()->getUserObject(0));
matrix.preMult(_matrix); matrix.preMult(_matrix);
osg::Vec3 scale = matrix.getScale();
matrix.setRotate(osg::Quat()); matrix.setRotate(osg::Quat());
matrix(0,0) = scale.x(); matrix(0,0) = userdata->mScale;
matrix(1,1) = scale.y(); matrix(1,1) = userdata->mScale;
matrix(2,2) = scale.z(); matrix(2,2) = userdata->mScale;
} }
else // absolute else // absolute
{ {
@ -365,7 +367,10 @@ namespace NifOsg
// - 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
transformNode->setUserData(new RecIndexHolder(nifNode->recIndex)); // - storing the previous 3x3 rotation and scale values for when a KeyframeController wants to
// change only certain elements of the 4x4 transform
transformNode->getOrCreateUserDataContainer()->addUserObject(
new NodeUserData(nifNode->recIndex, nifNode->trafo.scale, nifNode->trafo.rotation));
if (nifNode->recType == Nif::RC_NiBSAnimationNode) if (nifNode->recType == Nif::RC_NiBSAnimationNode)
animflags |= nifNode->flags; animflags |= nifNode->flags;
@ -471,7 +476,7 @@ namespace NifOsg
for (int j=0;j<3;++j) for (int j=0;j<3;++j)
mat(j,i) = nifNode->trafo.rotation.mValues[i][j]; mat(j,i) = nifNode->trafo.rotation.mValues[i][j];
osg::ref_ptr<KeyframeController> callback(new KeyframeController(mNif, key->data.getPtr(), mat.getRotate(), nifNode->trafo.scale)); osg::ref_ptr<KeyframeController> callback(new KeyframeController(mNif, key->data.getPtr()));
setupController(key, callback, animflags); setupController(key, callback, animflags);
transformNode->addUpdateCallback(callback); transformNode->addUpdateCallback(callback);

@ -8,6 +8,8 @@
#include <osg/io_utils> #include <osg/io_utils>
#include "userdata.hpp"
namespace NifOsg namespace NifOsg
{ {
@ -279,4 +281,26 @@ void Emitter::emitParticles(double dt)
} }
} }
FindRecIndexVisitor::FindRecIndexVisitor(int recIndex)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mFound(NULL)
, mRecIndex(recIndex)
{
}
void FindRecIndexVisitor::apply(osg::Node &searchNode)
{
if (searchNode.getUserDataContainer() && searchNode.getUserDataContainer()->getNumUserObjects())
{
NodeUserData* holder = dynamic_cast<NodeUserData*>(searchNode.getUserDataContainer()->getUserObject(0));
if (holder && holder->mIndex == mRecIndex)
{
mFound = static_cast<osg::Group*>(&searchNode);
mFoundPath = getNodePath();
return;
}
}
traverse(searchNode);
}
} }

@ -7,6 +7,7 @@
#include <osgParticle/ModularEmitter> #include <osgParticle/ModularEmitter>
#include <osg/NodeCallback> #include <osg/NodeCallback>
#include <osg/UserDataContainer>
#include <components/nif/nifkey.hpp> #include <components/nif/nifkey.hpp>
#include <components/nif/data.hpp> #include <components/nif/data.hpp>
@ -152,39 +153,13 @@ namespace NifOsg
osg::Vec3f mCachedWorldPositionDirection; osg::Vec3f mCachedWorldPositionDirection;
}; };
// NodeVisitor to find a child node with the given record index, stored in the node's user data container.
class RecIndexHolder : public osg::Referenced
{
public:
RecIndexHolder(int index) : mIndex(index) {}
int mIndex;
};
// NodeVisitor to find a child node with the given record index, stored in the node's user data.
class FindRecIndexVisitor : public osg::NodeVisitor class FindRecIndexVisitor : public osg::NodeVisitor
{ {
public: public:
FindRecIndexVisitor(int recIndex) FindRecIndexVisitor(int recIndex);
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mFound(NULL)
, mRecIndex(recIndex)
{
}
virtual void apply(osg::Node &searchNode) virtual void apply(osg::Node &searchNode);
{
if (searchNode.getUserData())
{
RecIndexHolder* holder = static_cast<RecIndexHolder*>(searchNode.getUserData());
if (holder->mIndex == mRecIndex)
{
mFound = static_cast<osg::Group*>(&searchNode);
mFoundPath = getNodePath();
return;
}
}
traverse(searchNode);
}
osg::Group* mFound; osg::Group* mFound;
osg::NodePath mFoundPath; osg::NodePath mFoundPath;

@ -0,0 +1,49 @@
#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,
// but then we have to fork osgAnimation :/
float mScale;
Nif::Matrix3 mRotationScale;
};
}
#endif
Loading…
Cancel
Save