mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
OSG-Collada animation support
This commit is contained in:
parent
f78a5d795c
commit
6e77ad1f6a
12 changed files with 471 additions and 23 deletions
|
@ -259,7 +259,7 @@ if(NOT HAVE_STDINT_H)
|
|||
endif()
|
||||
|
||||
|
||||
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX osgShadow)
|
||||
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX osgShadow osgAnimation)
|
||||
include_directories(SYSTEM ${OPENSCENEGRAPH_INCLUDE_DIRS})
|
||||
|
||||
set(USED_OSG_PLUGINS
|
||||
|
|
|
@ -782,6 +782,8 @@ namespace MWRender
|
|||
NodeMap::const_iterator found = nodeMap.find("bip01");
|
||||
if (found == nodeMap.end())
|
||||
found = nodeMap.find("root bone");
|
||||
if (found == nodeMap.end())
|
||||
found = nodeMap.find("root");
|
||||
|
||||
if (found != nodeMap.end())
|
||||
mAccumRoot = found->second;
|
||||
|
|
|
@ -41,7 +41,8 @@ add_component_dir (vfs
|
|||
)
|
||||
|
||||
add_component_dir (resource
|
||||
scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem resourcemanager stats
|
||||
scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem
|
||||
resourcemanager stats animation
|
||||
)
|
||||
|
||||
add_component_dir (shader
|
||||
|
@ -51,7 +52,7 @@ add_component_dir (shader
|
|||
add_component_dir (sceneutil
|
||||
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
|
||||
lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer
|
||||
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin
|
||||
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller
|
||||
)
|
||||
|
||||
add_component_dir (nif
|
||||
|
|
40
components/resource/animation.cpp
Normal file
40
components/resource/animation.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include <components/resource/animation.hpp>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgAnimation/Channel>
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
Animation::Animation(const Animation& anim, const osg::CopyOp& copyop): osg::Object(anim, copyop),
|
||||
mDuration(0.0f),
|
||||
mStartTime(0.0f)
|
||||
{
|
||||
const osgAnimation::ChannelList& channels = anim.getChannels();
|
||||
for (const osg::ref_ptr<osgAnimation::Channel> channel: channels)
|
||||
addChannel(channel.get()->clone());
|
||||
}
|
||||
|
||||
void Animation::addChannel(osg::ref_ptr<osgAnimation::Channel> pChannel)
|
||||
{
|
||||
mChannels.push_back(pChannel);
|
||||
}
|
||||
|
||||
std::vector<osg::ref_ptr<osgAnimation::Channel>>& Animation::getChannels()
|
||||
{
|
||||
return mChannels;
|
||||
}
|
||||
|
||||
const std::vector<osg::ref_ptr<osgAnimation::Channel>>& Animation::getChannels() const
|
||||
{
|
||||
return mChannels;
|
||||
}
|
||||
|
||||
bool Animation::update (double time)
|
||||
{
|
||||
for (const osg::ref_ptr<osgAnimation::Channel> channel: mChannels)
|
||||
{
|
||||
channel->update(time, 1.0f, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
39
components/resource/animation.hpp
Normal file
39
components/resource/animation.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef OPENMW_COMPONENTS_RESOURCE_ANIMATION_HPP
|
||||
#define OPENMW_COMPONENTS_RESOURCE_ANIMATION_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/Object>
|
||||
#include <osgAnimation/Channel>
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
/// Stripped down class of osgAnimation::Animation, only needed for OSG's plugin formats like dae
|
||||
class Animation : public osg::Object
|
||||
{
|
||||
public:
|
||||
META_Object(Resource, Animation)
|
||||
|
||||
Animation() :
|
||||
mDuration(0.0), mStartTime(0) {}
|
||||
|
||||
Animation(const Animation&, const osg::CopyOp&);
|
||||
~Animation() {}
|
||||
|
||||
void addChannel (osg::ref_ptr<osgAnimation::Channel> pChannel);
|
||||
|
||||
std::vector<osg::ref_ptr<osgAnimation::Channel>>& getChannels();
|
||||
|
||||
const std::vector<osg::ref_ptr<osgAnimation::Channel>>& getChannels() const;
|
||||
|
||||
bool update (double time);
|
||||
|
||||
protected:
|
||||
double mDuration;
|
||||
double mStartTime;
|
||||
std::vector<osg::ref_ptr<osgAnimation::Channel>> mChannels;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -2,29 +2,86 @@
|
|||
|
||||
#include <components/vfs/manager.hpp>
|
||||
|
||||
#include <components/nifosg/nifloader.hpp>
|
||||
#include <osgAnimation/Animation>
|
||||
#include <osgAnimation/BasicAnimationManager>
|
||||
#include <osgAnimation/Channel>
|
||||
|
||||
#include <components/nifosg/nifloader.hpp>
|
||||
#include <components/sceneutil/keyframe.hpp>
|
||||
#include <components/sceneutil/osgacontroller.hpp>
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "objectcache.hpp"
|
||||
#include "scenemanager.hpp"
|
||||
|
||||
namespace
|
||||
namespace OsgAOpenMW
|
||||
{
|
||||
class RetrieveAnimationsVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target) {}
|
||||
|
||||
RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target), mAnimationManager(animationManager) {}
|
||||
|
||||
virtual void apply(osg::Node& node)
|
||||
void RetrieveAnimationsVisitor::apply(osg::Node& node)
|
||||
{
|
||||
if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && node.getName() == std::string("root"))
|
||||
{
|
||||
if (!mAnimationManager)
|
||||
{
|
||||
if (node.libraryName() == std::string("osgAnimation"))
|
||||
std::cout << "found an " << node.className() << std::endl;
|
||||
traverse(node);
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
SceneUtil::KeyframeHolder& mTarget;
|
||||
};
|
||||
osg::ref_ptr<OsgaController::KeyframeController> callback = new OsgaController::KeyframeController();
|
||||
|
||||
std::vector<SceneUtil::EmulatedAnimation> emulatedAnimations;
|
||||
|
||||
for (auto animation : mAnimationManager->getAnimationList())
|
||||
{
|
||||
if (animation)
|
||||
{
|
||||
if (animation->getName() == "Default") //"Default" is osg dae plugin's default naming scheme for unnamed animations
|
||||
{
|
||||
animation->setName(std::string("idle")); // animation naming scheme "idle: start" and "idle: stop" is the default idle animation that OpenMW seems to want to play
|
||||
}
|
||||
|
||||
osg::ref_ptr<Resource::Animation> mergedAnimationTrack = new Resource::Animation;
|
||||
std::string animationName = animation->getName();
|
||||
std::string start = animationName + std::string(": start");
|
||||
std::string stop = animationName + std::string(": stop");
|
||||
std::string loopstart = animationName + std::string(": loop start");
|
||||
std::string loopstop = animationName + std::string(": loop stop");
|
||||
|
||||
const osgAnimation::ChannelList& channels = animation->getChannels();
|
||||
for (const osg::ref_ptr<osgAnimation::Channel> channel: channels)
|
||||
{
|
||||
mergedAnimationTrack->addChannel(channel.get()->clone()); // is ->clone needed?
|
||||
}
|
||||
mergedAnimationTrack->setName(animation->getName());
|
||||
callback->addMergedAnimationTrack(mergedAnimationTrack);
|
||||
|
||||
float startTime = animation->getStartTime();
|
||||
float stopTime = startTime + animation->getDuration();
|
||||
|
||||
// mTextKeys is a nif-thing, used by OpenMW's animation system
|
||||
// Format is likely "AnimationName: [Keyword_optional] [Start OR Stop]"
|
||||
// AnimationNames are keywords like idle2, idle3... AiPackages and various mechanics control which animations are played
|
||||
// Keywords can be stuff like Loop, Equip, Unequip, Block, InventoryHandtoHand, InventoryWeaponOneHand, PickProbe, Slash, Thrust, Chop... even "Slash Small Follow"
|
||||
mTarget.mTextKeys.emplace(startTime, std::move(start));
|
||||
mTarget.mTextKeys.emplace(stopTime, std::move(stop));
|
||||
mTarget.mTextKeys.emplace(startTime, std::move(loopstart));
|
||||
mTarget.mTextKeys.emplace(stopTime, std::move(loopstop));
|
||||
|
||||
SceneUtil::EmulatedAnimation emulatedAnimation;
|
||||
emulatedAnimation.mStartTime = startTime;
|
||||
emulatedAnimation.mStopTime = stopTime;
|
||||
emulatedAnimation.mName = animationName;
|
||||
emulatedAnimations.emplace_back(emulatedAnimation);
|
||||
}
|
||||
}
|
||||
callback->setEmulatedAnimations(emulatedAnimations);
|
||||
mTarget.mKeyframeControllers.emplace(node.getName(), callback);
|
||||
}
|
||||
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
std::string getFileExtension(const std::string& file)
|
||||
{
|
||||
|
@ -59,16 +116,17 @@ namespace Resource
|
|||
else
|
||||
{
|
||||
osg::ref_ptr<SceneUtil::KeyframeHolder> loaded (new SceneUtil::KeyframeHolder);
|
||||
std::string ext = getFileExtension(normalized);
|
||||
std::string ext = OsgAOpenMW::getFileExtension(normalized);
|
||||
if (ext == "kf")
|
||||
{
|
||||
NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::ref_ptr<const osg::Node> scene = mSceneManager->getTemplate(normalized);
|
||||
RetrieveAnimationsVisitor rav(*loaded.get());
|
||||
const_cast<osg::Node*>(scene.get())->accept(rav); // const_cast required because there is no const version of osg::NodeVisitor
|
||||
osg::ref_ptr<osg::Node> scene = const_cast<osg::Node*> ( mSceneManager->getTemplate(normalized).get() );
|
||||
osg::ref_ptr<osgAnimation::BasicAnimationManager> bam = dynamic_cast<osgAnimation::BasicAnimationManager*> (scene->getUpdateCallback());
|
||||
OsgAOpenMW::RetrieveAnimationsVisitor rav(*loaded.get(), bam);
|
||||
scene->accept(rav);
|
||||
}
|
||||
mCache->addEntryToObjectCache(normalized, loaded);
|
||||
return loaded;
|
||||
|
|
|
@ -2,12 +2,32 @@
|
|||
#define OPENMW_COMPONENTS_KEYFRAMEMANAGER_H
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgAnimation/BasicAnimationManager>
|
||||
#include <string>
|
||||
|
||||
#include <components/sceneutil/keyframe.hpp>
|
||||
|
||||
#include "resourcemanager.hpp"
|
||||
|
||||
namespace OsgAOpenMW
|
||||
{
|
||||
/// @brief extract animations to OpenMW's animation system
|
||||
class RetrieveAnimationsVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager);
|
||||
|
||||
virtual void apply(osg::Node& node);
|
||||
|
||||
private:
|
||||
SceneUtil::KeyframeHolder& mTarget;
|
||||
osg::ref_ptr<osgAnimation::BasicAnimationManager> mAnimationManager;
|
||||
|
||||
};
|
||||
|
||||
std::string getFileExtension(const std::string& file);
|
||||
}
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
|
||||
|
|
|
@ -492,7 +492,7 @@ namespace Resource
|
|||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2" };
|
||||
static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", "dae" };
|
||||
|
||||
for (unsigned int i=0; i<sizeof(sMeshTypes)/sizeof(sMeshTypes[0]); ++i)
|
||||
{
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
#include <osg/StateSet>
|
||||
|
||||
#include <osgAnimation/Bone>
|
||||
#include <osgAnimation/Skeleton>
|
||||
#include <osgAnimation/MorphGeometry>
|
||||
#include <osgAnimation/RigGeometry>
|
||||
|
||||
#include <osgParticle/ParticleProcessor>
|
||||
#include <osgParticle/ParticleSystemUpdater>
|
||||
#include <osgParticle/Emitter>
|
||||
|
@ -30,6 +35,11 @@ namespace SceneUtil
|
|||
mUpdaterToOldPs[cloned] = updater->getParticleSystem(0);
|
||||
return cloned;
|
||||
}
|
||||
|
||||
if (dynamic_cast<const osgAnimation::Bone*>(node) || dynamic_cast<const osgAnimation::Skeleton*>(node))
|
||||
{
|
||||
return osg::clone(node, *this);
|
||||
}
|
||||
return osg::CopyOp::operator()(node);
|
||||
}
|
||||
|
||||
|
@ -38,7 +48,7 @@ namespace SceneUtil
|
|||
if (const osgParticle::ParticleSystem* partsys = dynamic_cast<const osgParticle::ParticleSystem*>(drawable))
|
||||
return operator()(partsys);
|
||||
|
||||
if (dynamic_cast<const SceneUtil::RigGeometry*>(drawable) || dynamic_cast<const SceneUtil::MorphGeometry*>(drawable))
|
||||
if (dynamic_cast<const SceneUtil::RigGeometry*>(drawable) || dynamic_cast<const SceneUtil::MorphGeometry*>(drawable) || dynamic_cast<const osgAnimation::RigGeometry*>(drawable) || dynamic_cast<const osgAnimation::MorphGeometry*>(drawable))
|
||||
{
|
||||
return static_cast<osg::Drawable*>(drawable->clone(*this));
|
||||
}
|
||||
|
|
|
@ -7,9 +7,16 @@
|
|||
|
||||
#include <components/sceneutil/controller.hpp>
|
||||
#include <components/sceneutil/textkeymap.hpp>
|
||||
#include <components/resource/animation.hpp>
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
struct EmulatedAnimation
|
||||
{
|
||||
float mStartTime;
|
||||
float mStopTime;
|
||||
std::string mName;
|
||||
};
|
||||
|
||||
class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller
|
||||
{
|
||||
|
@ -19,12 +26,18 @@ namespace SceneUtil
|
|||
KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop)
|
||||
: osg::NodeCallback(copy, copyop)
|
||||
, SceneUtil::Controller(copy)
|
||||
, mMergedAnimationTracks(copy.mMergedAnimationTracks)
|
||||
, mEmulatedAnimations(copy.mEmulatedAnimations)
|
||||
{}
|
||||
META_Object(SceneUtil, KeyframeController)
|
||||
|
||||
virtual osg::Vec3f getTranslation(float time) const { return osg::Vec3f(); }
|
||||
|
||||
virtual void operator() (osg::Node* node, osg::NodeVisitor* nodeVisitor) { traverse(node, nodeVisitor); }
|
||||
|
||||
protected:
|
||||
std::vector<osg::ref_ptr<Resource::Animation>> mMergedAnimationTracks; // Used only by osgAnimation-based formats (e.g. dae)
|
||||
std::vector<EmulatedAnimation> mEmulatedAnimations;
|
||||
};
|
||||
|
||||
/// Wrapper object containing an animation track as a ref-countable osg::Object.
|
||||
|
|
195
components/sceneutil/osgacontroller.cpp
Normal file
195
components/sceneutil/osgacontroller.cpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include <components/sceneutil/osgacontroller.hpp>
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Node>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/StateSet>
|
||||
|
||||
#include <osgAnimation/Animation>
|
||||
#include <osgAnimation/AnimationUpdateCallback>
|
||||
#include <osgAnimation/Channel>
|
||||
#include <osgAnimation/BasicAnimationManager>
|
||||
#include <osgAnimation/Bone>
|
||||
#include <osgAnimation/Sampler>
|
||||
#include <osgAnimation/Skeleton>
|
||||
#include <osgAnimation/RigGeometry>
|
||||
#include <osgAnimation/UpdateMatrixTransform>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/resource/animation.hpp>
|
||||
#include <components/sceneutil/controller.hpp>
|
||||
#include <components/sceneutil/keyframe.hpp>
|
||||
|
||||
namespace OsgaController
|
||||
{
|
||||
LinkVisitor::LinkVisitor() : osg::NodeVisitor( TRAVERSE_ALL_CHILDREN )
|
||||
{
|
||||
mAnimation = nullptr;
|
||||
}
|
||||
|
||||
void LinkVisitor::link(osgAnimation::UpdateMatrixTransform* umt)
|
||||
{
|
||||
const osgAnimation::ChannelList& channels = mAnimation->getChannels();
|
||||
for (const osg::ref_ptr<osgAnimation::Channel> channel: channels)
|
||||
{
|
||||
const std::string& channelName = channel->getName();
|
||||
const std::string& channelTargetName = channel->getTargetName();
|
||||
|
||||
if (channelTargetName != umt->getName()) continue;
|
||||
|
||||
// check if we can link a StackedTransformElement to the current Channel
|
||||
for (auto stackedTransform : umt->getStackedTransforms())
|
||||
{
|
||||
osgAnimation::StackedTransformElement* element = stackedTransform.get();
|
||||
if (element && !element->getName().empty() && channelName == element->getName())
|
||||
{
|
||||
osgAnimation::Target* target = element->getOrCreateTarget();
|
||||
if (target)
|
||||
{
|
||||
channel->setTarget(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinkVisitor::handle_stateset(osg::StateSet* stateset)
|
||||
{
|
||||
if (!stateset)
|
||||
return;
|
||||
const osg::StateSet::AttributeList& attributeList = stateset->getAttributeList();
|
||||
for (auto attribute : attributeList)
|
||||
{
|
||||
osg::StateAttribute* sattr = attribute.second.first.get();
|
||||
osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(sattr->getUpdateCallback()); //Can this even be in sa?
|
||||
if (umt) link(umt);
|
||||
}
|
||||
}
|
||||
|
||||
void LinkVisitor::setAnimation(Resource::Animation* animation)
|
||||
{
|
||||
mAnimation = animation;
|
||||
}
|
||||
|
||||
void LinkVisitor::apply(osg::Node& node)
|
||||
{
|
||||
osg::StateSet* st = node.getStateSet();
|
||||
if (st)
|
||||
handle_stateset(st);
|
||||
|
||||
osg::Callback* cb = node.getUpdateCallback();
|
||||
while (cb)
|
||||
{
|
||||
osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(cb);
|
||||
if (umt)
|
||||
if (node.getName() != "root") link(umt);
|
||||
cb = cb->getNestedCallback();
|
||||
}
|
||||
|
||||
traverse( node );
|
||||
}
|
||||
|
||||
void LinkVisitor::apply(osg::Geode& node)
|
||||
{
|
||||
for (unsigned int i = 0; i < node.getNumDrawables(); i++)
|
||||
{
|
||||
osg::Drawable* drawable = node.getDrawable(i);
|
||||
if (drawable && drawable->getStateSet())
|
||||
handle_stateset(drawable->getStateSet());
|
||||
}
|
||||
apply(static_cast<osg::Node&>(node));
|
||||
}
|
||||
|
||||
KeyframeController::KeyframeController(const KeyframeController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop)
|
||||
{
|
||||
mLinker = nullptr;
|
||||
}
|
||||
|
||||
osg::Vec3f KeyframeController::getTranslation(float time) const
|
||||
{
|
||||
osg::Vec3f translationValue;
|
||||
std::string animationName;
|
||||
float newTime = time;
|
||||
|
||||
//Find the correct animation based on time
|
||||
for (auto emulatedAnimation : mEmulatedAnimations)
|
||||
{
|
||||
if (time > emulatedAnimation.mStartTime && time < emulatedAnimation.mStopTime)
|
||||
{
|
||||
newTime = time - emulatedAnimation.mStartTime;
|
||||
animationName = emulatedAnimation.mName;
|
||||
}
|
||||
}
|
||||
|
||||
//Find the root transform track in animation
|
||||
for (auto mergedAnimationTrack : mMergedAnimationTracks)
|
||||
{
|
||||
if (mergedAnimationTrack->getName() != animationName) continue;
|
||||
|
||||
const osgAnimation::ChannelList& channels = mergedAnimationTrack->getChannels();
|
||||
|
||||
for (const osg::ref_ptr<osgAnimation::Channel> channel: channels)
|
||||
{
|
||||
if (channel->getTargetName() != "root" || channel->getName() != "transform") continue;
|
||||
|
||||
if ( osgAnimation::MatrixLinearSampler* templateSampler = dynamic_cast<osgAnimation::MatrixLinearSampler*> (channel->getSampler()) )
|
||||
{
|
||||
osg::Matrixf matrix;
|
||||
templateSampler->getValueAt(newTime, matrix);
|
||||
translationValue = matrix.getTrans();
|
||||
return osg::Vec3f(translationValue[0], translationValue[1], translationValue[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return osg::Vec3f();
|
||||
}
|
||||
|
||||
void KeyframeController::update(float time, std::string animationName)
|
||||
{
|
||||
for (auto mergedAnimationTrack : mMergedAnimationTracks)
|
||||
{
|
||||
if (mergedAnimationTrack->getName() == animationName) mergedAnimationTrack->update(time);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
if (hasInput())
|
||||
{
|
||||
if (mNeedToLink)
|
||||
{
|
||||
for (auto mergedAnimationTrack : mMergedAnimationTracks)
|
||||
{
|
||||
if (!mLinker.valid()) mLinker = new LinkVisitor();
|
||||
mLinker->setAnimation(mergedAnimationTrack);
|
||||
node->accept(*mLinker);
|
||||
}
|
||||
mNeedToLink = false;
|
||||
}
|
||||
|
||||
float time = getInputValue(nv);
|
||||
|
||||
for (auto emulatedAnimation : mEmulatedAnimations)
|
||||
{
|
||||
if (time > emulatedAnimation.mStartTime && time < emulatedAnimation.mStopTime)
|
||||
{
|
||||
update(time - emulatedAnimation.mStartTime, emulatedAnimation.mName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverse(node, nv);
|
||||
}
|
||||
|
||||
void KeyframeController::setEmulatedAnimations(std::vector<SceneUtil::EmulatedAnimation> emulatedAnimations)
|
||||
{
|
||||
mEmulatedAnimations = emulatedAnimations;
|
||||
}
|
||||
|
||||
void KeyframeController::addMergedAnimationTrack(osg::ref_ptr<Resource::Animation> animationTrack)
|
||||
{
|
||||
mMergedAnimationTracks.emplace_back(animationTrack);
|
||||
}
|
||||
}
|
70
components/sceneutil/osgacontroller.hpp
Normal file
70
components/sceneutil/osgacontroller.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#ifndef OPENMW_COMPONENTS_SCENEUTIL_OSGACONTROLLER_HPP
|
||||
#define OPENMW_COMPONENTS_SCENEUTIL_OSGACONTROLLER_HPP
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osgAnimation/Animation>
|
||||
#include <osgAnimation/AnimationUpdateCallback>
|
||||
#include <osgAnimation/Channel>
|
||||
#include <osgAnimation/BasicAnimationManager>
|
||||
#include <osgAnimation/StackedTransform>
|
||||
#include <osgAnimation/UpdateMatrixTransform>
|
||||
|
||||
#include <components/sceneutil/controller.hpp>
|
||||
#include <components/sceneutil/keyframe.hpp>
|
||||
#include <components/resource/animation.hpp>
|
||||
|
||||
namespace OsgaController
|
||||
{
|
||||
class LinkVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
LinkVisitor();
|
||||
|
||||
virtual void link(osgAnimation::UpdateMatrixTransform* umt);
|
||||
|
||||
virtual void handle_stateset(osg::StateSet* stateset);
|
||||
|
||||
virtual void setAnimation(Resource::Animation* animation);
|
||||
|
||||
virtual void apply(osg::Node& node);
|
||||
|
||||
virtual void apply(osg::Geode& node);
|
||||
|
||||
protected:
|
||||
Resource::Animation* mAnimation;
|
||||
};
|
||||
|
||||
class KeyframeController : public SceneUtil::KeyframeController
|
||||
{
|
||||
public:
|
||||
/// @brief Handles the animation for osgAnimation formats
|
||||
KeyframeController() {};
|
||||
|
||||
KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop);
|
||||
|
||||
META_Object(OsgaController, KeyframeController)
|
||||
|
||||
/// @brief Handles the location of the instance
|
||||
osg::Vec3f getTranslation(float time) const override;
|
||||
|
||||
/// @brief Calls animation track update()
|
||||
void update(float time, std::string animationName);
|
||||
|
||||
/// @brief Called every frame for osgAnimation
|
||||
void operator() (osg::Node*, osg::NodeVisitor*) override;
|
||||
|
||||
/// @brief Sets details of the animations
|
||||
void setEmulatedAnimations(std::vector<SceneUtil::EmulatedAnimation> emulatedAnimations);
|
||||
|
||||
/// @brief Adds an animation track to a model
|
||||
void addMergedAnimationTrack(osg::ref_ptr<Resource::Animation> animationTrack);
|
||||
private:
|
||||
bool mNeedToLink = true;
|
||||
osg::ref_ptr<LinkVisitor> mLinker;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue