2014-01-05 18:22:29 +01:00
|
|
|
#ifndef GAME_RENDER_ANIMATION_H
|
|
|
|
#define GAME_RENDER_ANIMATION_H
|
2012-07-17 09:27:12 +02:00
|
|
|
|
2013-01-06 17:05:48 -08:00
|
|
|
#include "../mwworld/ptr.hpp"
|
|
|
|
|
2015-06-14 23:13:26 +02:00
|
|
|
#include <components/sceneutil/controller.hpp>
|
2020-11-18 22:48:47 +02:00
|
|
|
#include <components/sceneutil/textkeymap.hpp>
|
2019-08-07 11:03:26 +04:00
|
|
|
#include <components/sceneutil/util.hpp>
|
2021-10-05 12:21:12 +00:00
|
|
|
#include <components/sceneutil/nodecallback.hpp>
|
refactors a case insensitive map (#3184)
This PR aims to spark the retirement of a questionable pattern I have found all over our code base. I will illustrate how this pattern encourages code duplication, lacks type safety, requires documentation and can be prone to bugs.
```
std::map<std::string, Object> mMap; // Stored in all lowercase for a case-insensitive lookup
std::string lowerKey = Misc::StringUtils::lowerCase(key);
mMap.emplace(lowerKey, object);
std::string lowerKey = Misc::StringUtils::lowerCase(key);
mMap.find(lowerKey);
mMap.find(key); // Not found. Oops!
```
An alternative approach produces no such issues.
```
std::unordered_map<std::string, Object, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> mMap;
mMap.emplace(key, object);
mMap.find(key);
```
Of course, such an alternative will work for a `map` as well, but an `unordered_map` is generally preferable over a `map` with these changes because we have moved `lowerCase` into the comparison operator.
In this PR I have refactored `Animation::mNodeMap` accordingly. I have reviewed and adapted all direct and indirect usage of `Animation::mNodeMap` to ensure we do not change behaviour with this PR.
2021-10-25 07:18:26 +00:00
|
|
|
#include <components/misc/stringops.hpp>
|
2015-04-12 15:34:50 +02:00
|
|
|
|
2020-05-21 17:23:32 +02:00
|
|
|
#include <vector>
|
refactors a case insensitive map (#3184)
This PR aims to spark the retirement of a questionable pattern I have found all over our code base. I will illustrate how this pattern encourages code duplication, lacks type safety, requires documentation and can be prone to bugs.
```
std::map<std::string, Object> mMap; // Stored in all lowercase for a case-insensitive lookup
std::string lowerKey = Misc::StringUtils::lowerCase(key);
mMap.emplace(lowerKey, object);
std::string lowerKey = Misc::StringUtils::lowerCase(key);
mMap.find(lowerKey);
mMap.find(key); // Not found. Oops!
```
An alternative approach produces no such issues.
```
std::unordered_map<std::string, Object, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> mMap;
mMap.emplace(key, object);
mMap.find(key);
```
Of course, such an alternative will work for a `map` as well, but an `unordered_map` is generally preferable over a `map` with these changes because we have moved `lowerCase` into the comparison operator.
In this PR I have refactored `Animation::mNodeMap` accordingly. I have reviewed and adapted all direct and indirect usage of `Animation::mNodeMap` to ensure we do not change behaviour with this PR.
2021-10-25 07:18:26 +00:00
|
|
|
#include <unordered_map>
|
2020-05-21 17:23:32 +02:00
|
|
|
|
2014-02-23 20:11:05 +01:00
|
|
|
namespace ESM
|
|
|
|
{
|
|
|
|
struct Light;
|
2016-08-08 21:55:56 +09:00
|
|
|
struct MagicEffect;
|
2014-02-23 20:11:05 +01:00
|
|
|
}
|
2013-01-16 11:01:08 -08:00
|
|
|
|
2015-04-12 15:34:50 +02:00
|
|
|
namespace Resource
|
|
|
|
{
|
|
|
|
class ResourceSystem;
|
|
|
|
}
|
|
|
|
|
2020-11-18 22:48:47 +02:00
|
|
|
namespace SceneUtil
|
2015-04-23 20:41:31 +02:00
|
|
|
{
|
|
|
|
class KeyframeHolder;
|
2015-06-14 23:13:26 +02:00
|
|
|
class KeyframeController;
|
2015-07-02 17:19:30 +02:00
|
|
|
class LightSource;
|
2016-10-08 23:59:28 +02:00
|
|
|
class LightListCallback;
|
2015-12-03 20:06:00 +01:00
|
|
|
class Skeleton;
|
2015-07-02 17:19:30 +02:00
|
|
|
}
|
|
|
|
|
2013-01-05 21:12:08 -08:00
|
|
|
namespace MWRender
|
|
|
|
{
|
2011-12-11 22:40:00 -05:00
|
|
|
|
2015-04-23 22:46:07 +02:00
|
|
|
class ResetAccumRootCallback;
|
2015-06-22 21:06:27 +02:00
|
|
|
class RotateController;
|
2019-04-29 10:01:52 +04:00
|
|
|
class TransparencyUpdater;
|
2015-04-23 22:46:07 +02:00
|
|
|
|
2015-04-19 17:55:56 +02:00
|
|
|
class EffectAnimationTime : public SceneUtil::ControllerSource
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
float mTime;
|
|
|
|
public:
|
2020-10-16 22:18:54 +04:00
|
|
|
float getValue(osg::NodeVisitor* nv) override;
|
2015-04-19 17:55:56 +02:00
|
|
|
|
|
|
|
void addTime(float duration);
|
|
|
|
void resetTime(float time);
|
|
|
|
float getTime() const;
|
|
|
|
|
|
|
|
EffectAnimationTime() : mTime(0) { }
|
|
|
|
};
|
|
|
|
|
2015-05-31 01:07:43 +02:00
|
|
|
/// @brief Detaches the node from its parent when the object goes out of scope.
|
|
|
|
class PartHolder
|
|
|
|
{
|
|
|
|
public:
|
2015-06-14 23:13:26 +02:00
|
|
|
PartHolder(osg::ref_ptr<osg::Node> node);
|
2015-05-31 01:07:43 +02:00
|
|
|
|
2015-06-14 23:13:26 +02:00
|
|
|
~PartHolder();
|
2015-05-31 01:07:43 +02:00
|
|
|
|
|
|
|
osg::ref_ptr<osg::Node> getNode()
|
|
|
|
{
|
|
|
|
return mNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
osg::ref_ptr<osg::Node> mNode;
|
2015-11-11 01:47:11 +01:00
|
|
|
|
|
|
|
void operator= (const PartHolder&);
|
|
|
|
PartHolder(const PartHolder&);
|
2015-05-31 01:07:43 +02:00
|
|
|
};
|
2017-05-05 19:26:09 +02:00
|
|
|
typedef std::shared_ptr<PartHolder> PartHolderPtr;
|
2015-05-31 01:07:43 +02:00
|
|
|
|
2018-07-15 12:44:25 +04:00
|
|
|
struct EffectParams
|
|
|
|
{
|
|
|
|
std::string mModelName; // Just here so we don't add the same effect twice
|
|
|
|
std::shared_ptr<EffectAnimationTime> mAnimTime;
|
|
|
|
float mMaxControllerLength;
|
|
|
|
int mEffectId;
|
|
|
|
bool mLoop;
|
|
|
|
std::string mBoneName;
|
|
|
|
};
|
|
|
|
|
2017-02-22 15:22:40 +01:00
|
|
|
class Animation : public osg::Referenced
|
2013-01-05 21:12:08 -08:00
|
|
|
{
|
2013-05-10 18:37:44 -07:00
|
|
|
public:
|
2015-07-15 14:40:36 +02:00
|
|
|
enum BoneGroup {
|
|
|
|
BoneGroup_LowerBody = 0,
|
|
|
|
BoneGroup_Torso,
|
|
|
|
BoneGroup_LeftArm,
|
|
|
|
BoneGroup_RightArm
|
|
|
|
};
|
|
|
|
|
2015-07-09 18:47:11 +02:00
|
|
|
enum BlendMask {
|
|
|
|
BlendMask_LowerBody = 1<<0,
|
|
|
|
BlendMask_Torso = 1<<1,
|
|
|
|
BlendMask_LeftArm = 1<<2,
|
|
|
|
BlendMask_RightArm = 1<<3,
|
2013-05-13 01:58:13 -07:00
|
|
|
|
2015-07-09 18:47:11 +02:00
|
|
|
BlendMask_UpperBody = BlendMask_Torso | BlendMask_LeftArm | BlendMask_RightArm,
|
2013-05-10 20:45:09 -07:00
|
|
|
|
2015-07-09 18:47:11 +02:00
|
|
|
BlendMask_All = BlendMask_LowerBody | BlendMask_UpperBody
|
2013-05-10 20:05:09 -07:00
|
|
|
};
|
2015-07-15 14:40:36 +02:00
|
|
|
/* This is the number of *discrete* blend masks. */
|
2021-03-21 13:56:56 +01:00
|
|
|
static constexpr size_t sNumBlendMasks = 4;
|
2015-07-15 14:40:36 +02:00
|
|
|
|
|
|
|
/// Holds an animation priority value for each BoneGroup.
|
|
|
|
struct AnimPriority
|
|
|
|
{
|
|
|
|
/// Convenience constructor, initialises all priorities to the same value.
|
|
|
|
AnimPriority(int priority)
|
|
|
|
{
|
|
|
|
for (unsigned int i=0; i<sNumBlendMasks; ++i)
|
|
|
|
mPriority[i] = priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator == (const AnimPriority& other) const
|
|
|
|
{
|
|
|
|
for (unsigned int i=0; i<sNumBlendMasks; ++i)
|
|
|
|
if (other.mPriority[i] != mPriority[i])
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-16 16:14:17 +02:00
|
|
|
int& operator[] (BoneGroup n)
|
2015-09-16 15:43:42 +02:00
|
|
|
{
|
|
|
|
return mPriority[n];
|
|
|
|
}
|
|
|
|
|
2015-09-16 16:14:17 +02:00
|
|
|
const int& operator[] (BoneGroup n) const
|
2015-09-16 15:43:42 +02:00
|
|
|
{
|
|
|
|
return mPriority[n];
|
|
|
|
}
|
|
|
|
|
2015-07-15 14:40:36 +02:00
|
|
|
bool contains(int priority) const
|
|
|
|
{
|
|
|
|
for (unsigned int i=0; i<sNumBlendMasks; ++i)
|
|
|
|
if (priority == mPriority[i])
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mPriority[sNumBlendMasks];
|
|
|
|
};
|
2013-05-10 20:05:09 -07:00
|
|
|
|
2015-05-22 00:55:43 +02:00
|
|
|
class TextKeyListener
|
|
|
|
{
|
|
|
|
public:
|
2020-11-18 22:48:47 +02:00
|
|
|
virtual void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key,
|
|
|
|
const SceneUtil::TextKeyMap& map) = 0;
|
2020-03-26 12:07:32 +04:00
|
|
|
|
|
|
|
virtual ~TextKeyListener() = default;
|
2015-05-22 00:55:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
void setTextKeyListener(TextKeyListener* listener);
|
|
|
|
|
2019-08-11 15:01:48 +04:00
|
|
|
virtual bool updateCarriedLeftVisible(const int weaptype) const { return false; };
|
|
|
|
|
refactors a case insensitive map (#3184)
This PR aims to spark the retirement of a questionable pattern I have found all over our code base. I will illustrate how this pattern encourages code duplication, lacks type safety, requires documentation and can be prone to bugs.
```
std::map<std::string, Object> mMap; // Stored in all lowercase for a case-insensitive lookup
std::string lowerKey = Misc::StringUtils::lowerCase(key);
mMap.emplace(lowerKey, object);
std::string lowerKey = Misc::StringUtils::lowerCase(key);
mMap.find(lowerKey);
mMap.find(key); // Not found. Oops!
```
An alternative approach produces no such issues.
```
std::unordered_map<std::string, Object, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> mMap;
mMap.emplace(key, object);
mMap.find(key);
```
Of course, such an alternative will work for a `map` as well, but an `unordered_map` is generally preferable over a `map` with these changes because we have moved `lowerCase` into the comparison operator.
In this PR I have refactored `Animation::mNodeMap` accordingly. I have reviewed and adapted all direct and indirect usage of `Animation::mNodeMap` to ensure we do not change behaviour with this PR.
2021-10-25 07:18:26 +00:00
|
|
|
typedef std::unordered_map<std::string, osg::ref_ptr<osg::MatrixTransform>, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> NodeMap;
|
|
|
|
|
2012-07-12 20:12:18 -07:00
|
|
|
protected:
|
2015-04-22 19:08:56 +02:00
|
|
|
class AnimationTime : public SceneUtil::ControllerSource
|
2013-04-05 10:13:54 -07:00
|
|
|
{
|
|
|
|
private:
|
2017-05-05 19:26:09 +02:00
|
|
|
std::shared_ptr<float> mTimePtr;
|
2013-04-05 10:13:54 -07:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-05-05 19:26:09 +02:00
|
|
|
void setTimePtr(std::shared_ptr<float> time)
|
2015-05-14 16:33:41 +02:00
|
|
|
{ mTimePtr = time; }
|
2017-05-05 19:26:09 +02:00
|
|
|
std::shared_ptr<float> getTimePtr() const
|
2015-05-14 16:33:41 +02:00
|
|
|
{ return mTimePtr; }
|
2013-05-10 16:33:13 -07:00
|
|
|
|
2020-10-16 22:18:54 +04:00
|
|
|
float getValue(osg::NodeVisitor* nv) override;
|
2013-04-05 10:13:54 -07:00
|
|
|
};
|
2012-04-23 15:27:03 +02:00
|
|
|
|
2015-04-14 17:29:12 +02:00
|
|
|
class NullAnimationTime : public SceneUtil::ControllerSource
|
2013-07-23 22:05:03 -07:00
|
|
|
{
|
|
|
|
public:
|
2020-10-16 22:18:54 +04:00
|
|
|
float getValue(osg::NodeVisitor *nv) override
|
2015-04-12 15:34:50 +02:00
|
|
|
{
|
|
|
|
return 0.f;
|
|
|
|
}
|
2013-07-23 22:05:03 -07:00
|
|
|
};
|
|
|
|
|
2015-06-14 23:13:26 +02:00
|
|
|
struct AnimSource;
|
2015-04-23 20:41:31 +02:00
|
|
|
|
2013-05-10 04:01:30 -07:00
|
|
|
struct AnimState {
|
2017-05-05 19:26:09 +02:00
|
|
|
std::shared_ptr<AnimSource> mSource;
|
2013-07-24 08:38:36 -07:00
|
|
|
float mStartTime;
|
|
|
|
float mLoopStartTime;
|
|
|
|
float mLoopStopTime;
|
|
|
|
float mStopTime;
|
2013-04-22 23:35:50 -07:00
|
|
|
|
2017-05-05 19:26:09 +02:00
|
|
|
typedef std::shared_ptr<float> TimePtr;
|
2015-05-14 16:33:41 +02:00
|
|
|
TimePtr mTime;
|
2013-07-16 00:43:31 -07:00
|
|
|
float mSpeedMult;
|
2013-04-22 23:35:50 -07:00
|
|
|
|
|
|
|
bool mPlaying;
|
2016-08-18 01:08:54 +09:00
|
|
|
bool mLoopingEnabled;
|
2013-04-24 04:56:39 -07:00
|
|
|
size_t mLoopCount;
|
2013-04-22 23:35:50 -07:00
|
|
|
|
2015-07-15 14:18:31 +02:00
|
|
|
AnimPriority mPriority;
|
2015-07-09 18:47:11 +02:00
|
|
|
int mBlendMask;
|
2013-05-10 22:22:39 -07:00
|
|
|
bool mAutoDisable;
|
2013-05-10 18:37:44 -07:00
|
|
|
|
2013-07-24 08:38:36 -07:00
|
|
|
AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f),
|
2016-08-18 01:08:54 +09:00
|
|
|
mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopingEnabled(true),
|
|
|
|
mLoopCount(0), mPriority(0), mBlendMask(0), mAutoDisable(true)
|
2015-05-14 16:33:41 +02:00
|
|
|
{
|
|
|
|
}
|
2021-06-24 00:26:15 +02:00
|
|
|
~AnimState() = default;
|
2015-06-14 23:13:26 +02:00
|
|
|
|
2015-05-14 16:33:41 +02:00
|
|
|
float getTime() const
|
|
|
|
{
|
|
|
|
return *mTime;
|
|
|
|
}
|
|
|
|
void setTime(float time)
|
|
|
|
{
|
|
|
|
*mTime = time;
|
|
|
|
}
|
2016-08-22 22:58:24 +02:00
|
|
|
|
|
|
|
bool shouldLoop() const
|
|
|
|
{
|
|
|
|
return getTime() >= mLoopStopTime && mLoopingEnabled && mLoopCount > 0;
|
|
|
|
}
|
2013-04-24 04:41:52 -07:00
|
|
|
};
|
2013-05-10 04:01:30 -07:00
|
|
|
typedef std::map<std::string,AnimState> AnimStateMap;
|
2015-04-23 20:41:31 +02:00
|
|
|
AnimStateMap mStates;
|
|
|
|
|
2017-05-05 19:26:09 +02:00
|
|
|
typedef std::vector<std::shared_ptr<AnimSource> > AnimSourceList;
|
2015-04-23 20:41:31 +02:00
|
|
|
AnimSourceList mAnimSources;
|
2013-04-24 04:41:52 -07:00
|
|
|
|
2015-04-12 15:34:50 +02:00
|
|
|
osg::ref_ptr<osg::Group> mInsert;
|
2013-11-13 14:02:15 +01:00
|
|
|
|
2015-12-17 03:48:11 +01:00
|
|
|
osg::ref_ptr<osg::Group> mObjectRoot;
|
2015-12-03 20:06:00 +01:00
|
|
|
SceneUtil::Skeleton* mSkeleton;
|
2013-11-11 23:43:28 +01:00
|
|
|
|
2015-04-23 20:41:31 +02:00
|
|
|
// The node expected to accumulate movement during movement animations.
|
|
|
|
osg::ref_ptr<osg::Node> mAccumRoot;
|
|
|
|
|
|
|
|
// The controller animating that node.
|
2020-11-18 22:48:47 +02:00
|
|
|
osg::ref_ptr<SceneUtil::KeyframeController> mAccumCtrl;
|
2015-04-23 20:41:31 +02:00
|
|
|
|
2015-04-23 22:46:07 +02:00
|
|
|
// Used to reset the position of the accumulation root every frame - the movement should be applied to the physics system
|
|
|
|
osg::ref_ptr<ResetAccumRootCallback> mResetAccumRootCallback;
|
|
|
|
|
2015-05-31 02:26:31 +02:00
|
|
|
// Keep track of controllers that we added to our scene graph.
|
2015-04-23 20:41:31 +02:00
|
|
|
// We may need to rebuild these controllers when the active animation groups / sources change.
|
2021-10-04 08:56:55 +00:00
|
|
|
std::vector<std::pair<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::Callback>>> mActiveControllers;
|
2015-04-23 20:41:31 +02:00
|
|
|
|
2017-05-05 19:26:09 +02:00
|
|
|
std::shared_ptr<AnimationTime> mAnimationTimePtr[sNumBlendMasks];
|
2015-04-23 20:41:31 +02:00
|
|
|
|
2016-02-09 16:18:19 +01:00
|
|
|
mutable NodeMap mNodeMap;
|
|
|
|
mutable bool mNodeMapCreated;
|
2015-04-23 20:41:31 +02:00
|
|
|
|
2013-04-24 04:41:52 -07:00
|
|
|
MWWorld::Ptr mPtr;
|
|
|
|
|
2015-04-12 15:34:50 +02:00
|
|
|
Resource::ResourceSystem* mResourceSystem;
|
2013-11-11 23:43:28 +01:00
|
|
|
|
2015-04-23 20:41:31 +02:00
|
|
|
osg::Vec3f mAccumulate;
|
|
|
|
|
2015-05-22 00:55:43 +02:00
|
|
|
TextKeyListener* mTextKeyListener;
|
|
|
|
|
2015-06-22 21:06:27 +02:00
|
|
|
osg::ref_ptr<RotateController> mHeadController;
|
2020-06-22 02:03:38 +02:00
|
|
|
osg::ref_ptr<RotateController> mSpineController;
|
|
|
|
osg::ref_ptr<RotateController> mRootController;
|
2015-06-22 21:06:27 +02:00
|
|
|
float mHeadYawRadians;
|
|
|
|
float mHeadPitchRadians;
|
2020-06-22 02:03:38 +02:00
|
|
|
float mUpperBodyYawRadians;
|
|
|
|
float mLegsYawRadians;
|
2020-07-09 06:47:37 +00:00
|
|
|
float mBodyPitchRadians;
|
2020-06-22 02:03:38 +02:00
|
|
|
|
2021-08-15 19:50:28 +02:00
|
|
|
RotateController* addRotateController(const std::string& bone);
|
2020-06-22 02:03:38 +02:00
|
|
|
|
2018-08-26 21:02:14 +04:00
|
|
|
bool mHasMagicEffects;
|
2015-06-22 21:06:27 +02:00
|
|
|
|
2015-07-02 17:19:30 +02:00
|
|
|
osg::ref_ptr<SceneUtil::LightSource> mGlowLight;
|
2019-08-07 11:03:26 +04:00
|
|
|
osg::ref_ptr<SceneUtil::GlowUpdater> mGlowUpdater;
|
2019-04-29 10:01:52 +04:00
|
|
|
osg::ref_ptr<TransparencyUpdater> mTransparencyUpdater;
|
2021-04-05 10:43:17 -07:00
|
|
|
osg::ref_ptr<SceneUtil::LightSource> mExtraLightSource;
|
2015-07-02 17:19:30 +02:00
|
|
|
|
2015-09-16 16:15:55 +02:00
|
|
|
float mAlpha;
|
|
|
|
|
2017-02-04 17:41:41 +01:00
|
|
|
mutable std::map<std::string, float> mAnimVelocities;
|
|
|
|
|
2016-10-08 23:59:28 +02:00
|
|
|
osg::ref_ptr<SceneUtil::LightListCallback> mLightListCallback;
|
|
|
|
|
2016-02-09 16:18:19 +01:00
|
|
|
const NodeMap& getNodeMap() const;
|
|
|
|
|
2013-05-10 18:37:44 -07:00
|
|
|
/* Sets the appropriate animations on the bone groups based on priority.
|
|
|
|
*/
|
2015-04-23 20:41:31 +02:00
|
|
|
void resetActiveGroups();
|
2013-05-10 18:37:44 -07:00
|
|
|
|
2016-05-19 22:30:14 +02:00
|
|
|
size_t detectBlendMask(const osg::Node* node) const;
|
2013-01-30 09:29:16 -08:00
|
|
|
|
2013-05-10 03:08:07 -07:00
|
|
|
/* Updates the position of the accum root node for the given time, and
|
2013-05-10 18:58:14 -07:00
|
|
|
* returns the wanted movement vector from the previous time. */
|
2015-04-23 22:46:07 +02:00
|
|
|
void updatePosition(float oldtime, float newtime, osg::Vec3f& position);
|
2012-04-23 15:27:03 +02:00
|
|
|
|
2013-02-23 05:15:10 -08:00
|
|
|
/* Resets the animation to the time of the specified start marker, without
|
|
|
|
* moving anything, and set the end time to the specified stop marker. If
|
2013-04-22 20:41:54 -07:00
|
|
|
* the marker is not found, or if the markers are the same, it returns
|
|
|
|
* false.
|
2013-02-23 05:15:10 -08:00
|
|
|
*/
|
2020-11-18 22:48:47 +02:00
|
|
|
bool reset(AnimState &state, const SceneUtil::TextKeyMap &keys,
|
2015-04-23 20:41:31 +02:00
|
|
|
const std::string &groupname, const std::string &start, const std::string &stop,
|
|
|
|
float startpoint, bool loopfallback);
|
2012-07-24 13:51:48 -07:00
|
|
|
|
2020-11-18 22:48:47 +02:00
|
|
|
void handleTextKey(AnimState &state, const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key,
|
|
|
|
const SceneUtil::TextKeyMap& map);
|
2013-02-23 14:39:01 -08:00
|
|
|
|
2015-04-23 23:30:06 +02:00
|
|
|
/** Sets the root model of the object.
|
2013-07-08 18:59:51 -07:00
|
|
|
*
|
2016-12-14 16:39:33 +01:00
|
|
|
* Note that you must make sure all animation sources are cleared before resetting the object
|
2013-07-08 18:59:51 -07:00
|
|
|
* root. All nodes previously retrieved with getNode will also become invalidated.
|
2015-04-23 23:30:06 +02:00
|
|
|
* @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually.
|
2015-05-21 23:24:22 +02:00
|
|
|
* @param baseonly If true, then any meshes or particle systems in the model are ignored
|
|
|
|
* (useful for NPCs, where only the skeleton is needed for the root, and the actual NPC parts are then assembled from separate files).
|
2013-07-08 18:59:51 -07:00
|
|
|
*/
|
2015-08-15 19:01:21 +02:00
|
|
|
void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature);
|
2013-07-08 18:59:51 -07:00
|
|
|
|
2018-05-30 08:54:43 +04:00
|
|
|
void loadAllAnimationsInFolder(const std::string &model, const std::string &baseModel);
|
|
|
|
|
2017-11-10 22:02:43 +01:00
|
|
|
/** Adds the keyframe controllers in the specified model as a new animation source.
|
2016-02-03 14:40:59 +01:00
|
|
|
* @note Later added animation sources have the highest priority when it comes to finding a particular animation.
|
2017-11-10 22:02:43 +01:00
|
|
|
* @param model The file to add the keyframes for. Note that the .nif file extension will be replaced with .kf.
|
|
|
|
* @param baseModel The filename of the mObjectRoot, only used for error messages.
|
2016-02-03 14:40:59 +01:00
|
|
|
*/
|
2017-11-10 22:02:43 +01:00
|
|
|
void addAnimSource(const std::string &model, const std::string& baseModel);
|
2018-05-30 08:54:43 +04:00
|
|
|
void addSingleAnimSource(const std::string &model, const std::string& baseModel);
|
2013-05-06 23:11:26 -07:00
|
|
|
|
2015-04-19 15:03:08 +02:00
|
|
|
/** Adds an additional light to the given node using the specified ESM record. */
|
|
|
|
void addExtraLight(osg::ref_ptr<osg::Group> parent, const ESM::Light *light);
|
2013-05-07 16:59:32 -07:00
|
|
|
|
2015-04-23 23:30:06 +02:00
|
|
|
void clearAnimSources();
|
2013-11-20 00:07:26 +01:00
|
|
|
|
2015-05-31 02:26:31 +02:00
|
|
|
/**
|
|
|
|
* Provided to allow derived classes adding their own controllers. Note, the controllers must be added to mActiveControllers
|
|
|
|
* so they get cleaned up properly on the next controller rebuild. A controller rebuild may be necessary to ensure correct ordering.
|
|
|
|
*/
|
2015-06-22 21:06:27 +02:00
|
|
|
virtual void addControllers();
|
2015-05-31 02:26:31 +02:00
|
|
|
|
2012-07-12 20:12:18 -07:00
|
|
|
public:
|
2014-01-17 10:52:44 +01:00
|
|
|
|
2015-04-15 22:11:38 +02:00
|
|
|
Animation(const MWWorld::Ptr &ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem);
|
2017-02-22 15:22:40 +01:00
|
|
|
|
|
|
|
/// Must be thread safe
|
2012-07-12 20:12:18 -07:00
|
|
|
virtual ~Animation();
|
2012-07-20 00:53:12 -07:00
|
|
|
|
2016-05-19 22:30:14 +02:00
|
|
|
MWWorld::ConstPtr getPtr() const;
|
2015-05-21 23:54:39 +02:00
|
|
|
|
2017-02-22 14:54:40 +01:00
|
|
|
MWWorld::Ptr getPtr();
|
|
|
|
|
2015-04-29 23:48:08 +02:00
|
|
|
/// Set active flag on the object skeleton, if one exists.
|
|
|
|
/// @see SceneUtil::Skeleton::setActive
|
2018-01-11 01:49:35 +00:00
|
|
|
/// 0 = Inactive, 1 = Active in place, 2 = Active
|
|
|
|
void setActive(int active);
|
2015-04-29 23:48:08 +02:00
|
|
|
|
2015-04-12 15:34:50 +02:00
|
|
|
osg::Group* getOrCreateObjectRoot();
|
|
|
|
|
|
|
|
osg::Group* getObjectRoot();
|
|
|
|
|
2013-11-13 14:02:15 +01:00
|
|
|
/**
|
|
|
|
* @brief Add an effect mesh attached to a bone or the insert scene node
|
|
|
|
* @param model
|
2014-06-15 21:19:37 +02:00
|
|
|
* @param effectId An ID for this effect by which you can identify it later. If this is not wanted, set to -1.
|
2013-11-13 14:02:15 +01:00
|
|
|
* @param loop Loop the effect. If false, it is removed automatically after it finishes playing. If true,
|
|
|
|
* you need to remove it manually using removeEffect when the effect should end.
|
|
|
|
* @param bonename Bone to attach to, or empty string to use the scene node instead
|
2015-04-19 01:57:52 +02:00
|
|
|
* @param texture override the texture specified in the model's materials - if empty, do not override
|
2013-11-13 14:02:15 +01:00
|
|
|
* @note Will not add an effect twice.
|
|
|
|
*/
|
2019-04-21 18:04:27 +03:00
|
|
|
void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", const std::string& texture = "");
|
2015-04-19 01:57:52 +02:00
|
|
|
void removeEffect (int effectId);
|
2018-09-28 13:57:13 +04:00
|
|
|
void removeEffects ();
|
2016-05-19 22:30:14 +02:00
|
|
|
void getLoopingEffects (std::vector<int>& out) const;
|
2013-12-08 23:05:21 +01:00
|
|
|
|
2016-08-23 23:13:37 +09:00
|
|
|
// Add a spell casting glow to an object. From measuring video taken from the original engine,
|
|
|
|
// the glow seems to be about 1.5 seconds except for telekinesis, which is 1 second.
|
|
|
|
void addSpellCastGlow(const ESM::MagicEffect *effect, float glowDuration = 1.5);
|
2016-08-02 21:37:39 +09:00
|
|
|
|
2015-05-14 17:34:55 +02:00
|
|
|
virtual void updatePtr(const MWWorld::Ptr &ptr);
|
2013-12-26 18:16:28 +01:00
|
|
|
|
2016-05-19 22:30:14 +02:00
|
|
|
bool hasAnimation(const std::string &anim) const;
|
2013-01-16 15:00:06 -08:00
|
|
|
|
2013-01-18 14:25:32 -08:00
|
|
|
// Specifies the axis' to accumulate on. Non-accumulated axis will just
|
|
|
|
// move visually, but not affect the actual movement. Each x/y/z value
|
|
|
|
// should be on the scale of 0 to 1.
|
2015-04-23 20:41:31 +02:00
|
|
|
void setAccumulation(const osg::Vec3f& accum);
|
2013-01-18 14:25:32 -08:00
|
|
|
|
2013-04-24 19:09:36 -07:00
|
|
|
/** Plays an animation.
|
|
|
|
* \param groupname Name of the animation group to play.
|
2013-05-10 18:37:44 -07:00
|
|
|
* \param priority Priority of the animation. The animation will play on
|
|
|
|
* bone groups that don't have another animation set of a
|
|
|
|
* higher priority.
|
2015-07-09 18:47:11 +02:00
|
|
|
* \param blendMask Bone groups to play the animation on.
|
2013-05-10 22:22:39 -07:00
|
|
|
* \param autodisable Automatically disable the animation when it stops
|
|
|
|
* playing.
|
2013-07-16 00:43:31 -07:00
|
|
|
* \param speedmult Speed multiplier for the animation.
|
2013-04-24 19:09:36 -07:00
|
|
|
* \param start Key marker from which to start.
|
|
|
|
* \param stop Key marker to stop at.
|
|
|
|
* \param startpoint How far in between the two markers to start. 0 starts
|
|
|
|
* at the start marker, 1 starts at the stop marker.
|
|
|
|
* \param loops How many times to loop the animation. This will use the
|
|
|
|
* "loop start" and "loop stop" markers if they exist,
|
2014-12-21 15:29:20 +01:00
|
|
|
* otherwise it may fall back to "start" and "stop", but only if
|
|
|
|
* the \a loopFallback parameter is true.
|
|
|
|
* \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use
|
|
|
|
* the "start" and "stop" keys for looping?
|
2013-04-24 19:09:36 -07:00
|
|
|
*/
|
2015-07-18 03:23:41 +02:00
|
|
|
void play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable,
|
2015-04-23 20:41:31 +02:00
|
|
|
float speedmult, const std::string &start, const std::string &stop,
|
|
|
|
float startpoint, size_t loops, bool loopfallback=false);
|
2013-04-25 00:03:27 -07:00
|
|
|
|
2014-09-17 05:20:10 +02:00
|
|
|
/** Adjust the speed multiplier of an already playing animation.
|
|
|
|
*/
|
2015-04-23 20:41:31 +02:00
|
|
|
void adjustSpeedMult (const std::string& groupname, float speedmult);
|
2014-09-17 05:20:10 +02:00
|
|
|
|
2013-05-12 05:08:01 -07:00
|
|
|
/** Returns true if the named animation group is playing. */
|
2015-04-23 20:41:31 +02:00
|
|
|
bool isPlaying(const std::string &groupname) const;
|
2013-05-12 05:08:01 -07:00
|
|
|
|
2014-08-28 00:41:52 +02:00
|
|
|
/// Returns true if no important animations are currently playing on the upper body.
|
2015-05-12 17:40:42 +02:00
|
|
|
bool upperBodyReady() const;
|
2013-12-27 00:36:06 +01:00
|
|
|
|
2013-05-10 03:08:07 -07:00
|
|
|
/** Gets info about the given animation group.
|
|
|
|
* \param groupname Animation group to check.
|
2013-04-25 00:03:27 -07:00
|
|
|
* \param complete Stores completion amount (0 = at start key, 0.5 = half way between start and stop keys), etc.
|
2013-07-16 00:43:31 -07:00
|
|
|
* \param speedmult Stores the animation speed multiplier
|
2013-05-10 03:08:07 -07:00
|
|
|
* \return True if the animation is active, false otherwise.
|
2013-04-25 00:03:27 -07:00
|
|
|
*/
|
2018-10-09 10:21:12 +04:00
|
|
|
bool getInfo(const std::string &groupname, float *complete=nullptr, float *speedmult=nullptr) const;
|
2013-04-25 00:03:27 -07:00
|
|
|
|
2014-02-04 03:46:15 +01:00
|
|
|
/// Get the absolute position in the animation track of the first text key with the given group.
|
2015-04-23 20:41:31 +02:00
|
|
|
float getStartTime(const std::string &groupname) const;
|
2014-06-11 00:20:46 +04:00
|
|
|
|
|
|
|
/// Get the absolute position in the animation track of the text key
|
2015-04-23 20:41:31 +02:00
|
|
|
float getTextKeyTime(const std::string &textKey) const;
|
2014-02-04 03:46:15 +01:00
|
|
|
|
|
|
|
/// Get the current absolute position in the animation track for the animation that is currently playing from the given group.
|
2015-04-23 20:41:31 +02:00
|
|
|
float getCurrentTime(const std::string& groupname) const;
|
2014-02-04 03:46:15 +01:00
|
|
|
|
2016-07-30 19:24:03 +02:00
|
|
|
size_t getCurrentLoopCount(const std::string& groupname) const;
|
|
|
|
|
2013-05-10 22:22:39 -07:00
|
|
|
/** Disables the specified animation group;
|
|
|
|
* \param groupname Animation group to disable.
|
|
|
|
*/
|
2015-04-23 20:41:31 +02:00
|
|
|
void disable(const std::string &groupname);
|
2014-02-04 03:46:15 +01:00
|
|
|
|
2013-07-16 01:30:03 -07:00
|
|
|
/** Retrieves the velocity (in units per second) that the animation will move. */
|
2015-04-23 20:41:31 +02:00
|
|
|
float getVelocity(const std::string &groupname) const;
|
2015-04-12 15:34:50 +02:00
|
|
|
|
|
|
|
virtual osg::Vec3f runAnimation(float duration);
|
2015-04-19 01:57:52 +02:00
|
|
|
|
2016-08-18 01:08:54 +09:00
|
|
|
void setLoopingEnabled(const std::string &groupname, bool enabled);
|
|
|
|
|
2018-05-26 11:39:30 +00:00
|
|
|
/// This is typically called as part of runAnimation, but may be called manually if needed.
|
2018-08-26 21:02:14 +04:00
|
|
|
void updateEffects();
|
2015-04-23 20:41:31 +02:00
|
|
|
|
2018-10-09 10:21:12 +04:00
|
|
|
/// Return a node with the specified name, or nullptr if not existing.
|
2015-05-20 02:18:20 +02:00
|
|
|
/// @note The matching is case-insensitive.
|
|
|
|
const osg::Node* getNode(const std::string& name) const;
|
2015-04-25 01:20:07 +02:00
|
|
|
|
2019-08-11 15:01:48 +04:00
|
|
|
virtual bool useShieldAnimations() const { return false; }
|
2015-04-25 01:20:07 +02:00
|
|
|
virtual void showWeapons(bool showWeapon) {}
|
2020-04-04 19:20:52 +03:00
|
|
|
virtual bool getCarriedLeftShown() const { return false; }
|
2015-04-25 01:20:07 +02:00
|
|
|
virtual void showCarriedLeft(bool show) {}
|
2019-03-05 13:33:58 +04:00
|
|
|
virtual void setWeaponGroup(const std::string& group, bool relativeDuration) {}
|
2015-04-25 01:20:07 +02:00
|
|
|
virtual void setVampire(bool vampire) {}
|
2015-09-16 16:15:55 +02:00
|
|
|
/// A value < 1 makes the animation translucent, 1.f = fully opaque
|
|
|
|
void setAlpha(float alpha);
|
2015-04-25 01:20:07 +02:00
|
|
|
virtual void setPitchFactor(float factor) {}
|
|
|
|
virtual void attachArrow() {}
|
2020-08-28 15:28:26 +04:00
|
|
|
virtual void detachArrow() {}
|
2015-06-26 05:15:07 +02:00
|
|
|
virtual void releaseArrow(float attackStrength) {}
|
2015-04-25 01:20:07 +02:00
|
|
|
virtual void enableHeadAnimation(bool enable) {}
|
|
|
|
// TODO: move outside of this class
|
|
|
|
/// Makes this object glow, by placing a Light in its center.
|
|
|
|
/// @param effect Controls the radius and intensity of the light.
|
2015-07-02 17:19:30 +02:00
|
|
|
virtual void setLightEffect(float effect);
|
2015-04-25 01:20:07 +02:00
|
|
|
|
2015-06-22 21:06:27 +02:00
|
|
|
virtual void setHeadPitch(float pitchRadians);
|
|
|
|
virtual void setHeadYaw(float yawRadians);
|
|
|
|
virtual float getHeadPitch() const;
|
|
|
|
virtual float getHeadYaw() const;
|
2020-06-22 02:03:38 +02:00
|
|
|
|
|
|
|
virtual void setUpperBodyYawRadians(float v) { mUpperBodyYawRadians = v; }
|
|
|
|
virtual void setLegsYawRadians(float v) { mLegsYawRadians = v; }
|
|
|
|
virtual float getUpperBodyYawRadians() const { return mUpperBodyYawRadians; }
|
|
|
|
virtual float getLegsYawRadians() const { return mLegsYawRadians; }
|
2020-07-09 06:47:37 +00:00
|
|
|
virtual void setBodyPitchRadians(float v) { mBodyPitchRadians = v; }
|
|
|
|
virtual float getBodyPitchRadians() const { return mBodyPitchRadians; }
|
2020-06-22 02:03:38 +02:00
|
|
|
|
2015-11-10 01:01:41 +01:00
|
|
|
virtual void setAccurateAiming(bool enabled) {}
|
2018-12-03 20:21:40 +04:00
|
|
|
virtual bool canBeHarvested() const { return false; }
|
2015-05-31 18:04:14 +02:00
|
|
|
|
2015-04-23 20:41:31 +02:00
|
|
|
private:
|
|
|
|
Animation(const Animation&);
|
|
|
|
void operator=(Animation&);
|
2011-11-24 01:48:54 -05:00
|
|
|
};
|
2012-07-12 20:12:18 -07:00
|
|
|
|
2013-08-06 19:45:07 -07:00
|
|
|
class ObjectAnimation : public Animation {
|
|
|
|
public:
|
2015-05-28 15:44:58 +02:00
|
|
|
ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool animated, bool allowLight);
|
2018-12-03 20:21:40 +04:00
|
|
|
|
2020-10-16 22:18:54 +04:00
|
|
|
bool canBeHarvested() const override;
|
2013-08-06 19:45:07 -07:00
|
|
|
};
|
|
|
|
|
2021-10-05 12:21:12 +00:00
|
|
|
class UpdateVfxCallback : public SceneUtil::NodeCallback<UpdateVfxCallback>
|
2018-07-15 12:44:25 +04:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
UpdateVfxCallback(EffectParams& params)
|
|
|
|
: mFinished(false)
|
|
|
|
, mParams(params)
|
|
|
|
, mStartingTime(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool mFinished;
|
|
|
|
EffectParams mParams;
|
|
|
|
|
2021-10-05 12:21:12 +00:00
|
|
|
void operator()(osg::Node* node, osg::NodeVisitor* nv);
|
2018-07-15 12:44:25 +04:00
|
|
|
|
|
|
|
private:
|
|
|
|
double mStartingTime;
|
|
|
|
};
|
|
|
|
|
2011-11-24 01:48:54 -05:00
|
|
|
}
|
2012-03-25 21:56:22 +02:00
|
|
|
#endif
|