mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:53:50 +00:00
Change rotation/scale workaround in preparation for loading .kf controllers
This commit is contained in:
parent
15f9c1ddcf
commit
2db5df77f0
8 changed files with 121 additions and 53 deletions
|
@ -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 ©, 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;
|
||||||
|
|
49
components/nifosg/userdata.hpp
Normal file
49
components/nifosg/userdata.hpp
Normal file
|
@ -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…
Reference in a new issue