1 #ifndef GAME_RENDER_ANIMATION_H
2 #define GAME_RENDER_ANIMATION_H
3 
4 #include "../mwworld/ptr.hpp"
5 
6 #include <components/sceneutil/controller.hpp>
7 #include <components/sceneutil/textkeymap.hpp>
8 #include <components/sceneutil/util.hpp>
9 
10 #include <vector>
11 
12 namespace ESM
13 {
14     struct Light;
15     struct MagicEffect;
16 }
17 
18 namespace Resource
19 {
20     class ResourceSystem;
21 }
22 
23 namespace SceneUtil
24 {
25     class KeyframeHolder;
26     class KeyframeController;
27     class LightSource;
28     class LightListCallback;
29     class Skeleton;
30 }
31 
32 namespace MWRender
33 {
34 
35 class ResetAccumRootCallback;
36 class RotateController;
37 class TransparencyUpdater;
38 
39 class EffectAnimationTime : public SceneUtil::ControllerSource
40 {
41 private:
42     float mTime;
43 public:
44     float getValue(osg::NodeVisitor* nv) override;
45 
46     void addTime(float duration);
47     void resetTime(float time);
48     float getTime() const;
49 
EffectAnimationTime()50     EffectAnimationTime() : mTime(0) {  }
51 };
52 
53 /// @brief Detaches the node from its parent when the object goes out of scope.
54 class PartHolder
55 {
56 public:
57     PartHolder(osg::ref_ptr<osg::Node> node);
58 
59     ~PartHolder();
60 
getNode()61     osg::ref_ptr<osg::Node> getNode()
62     {
63         return mNode;
64     }
65 
66 private:
67     osg::ref_ptr<osg::Node> mNode;
68 
69     void operator= (const PartHolder&);
70     PartHolder(const PartHolder&);
71 };
72 typedef std::shared_ptr<PartHolder> PartHolderPtr;
73 
74 struct EffectParams
75 {
76     std::string mModelName; // Just here so we don't add the same effect twice
77     std::shared_ptr<EffectAnimationTime> mAnimTime;
78     float mMaxControllerLength;
79     int mEffectId;
80     bool mLoop;
81     std::string mBoneName;
82 };
83 
84 class Animation : public osg::Referenced
85 {
86 public:
87     enum BoneGroup {
88         BoneGroup_LowerBody = 0,
89         BoneGroup_Torso,
90         BoneGroup_LeftArm,
91         BoneGroup_RightArm
92     };
93 
94     enum BlendMask {
95         BlendMask_LowerBody = 1<<0,
96         BlendMask_Torso = 1<<1,
97         BlendMask_LeftArm = 1<<2,
98         BlendMask_RightArm = 1<<3,
99 
100         BlendMask_UpperBody = BlendMask_Torso | BlendMask_LeftArm | BlendMask_RightArm,
101 
102         BlendMask_All = BlendMask_LowerBody | BlendMask_UpperBody
103     };
104     /* This is the number of *discrete* blend masks. */
105     static constexpr size_t sNumBlendMasks = 4;
106 
107     /// Holds an animation priority value for each BoneGroup.
108     struct AnimPriority
109     {
110         /// Convenience constructor, initialises all priorities to the same value.
AnimPriorityMWRender::Animation::AnimPriority111         AnimPriority(int priority)
112         {
113             for (unsigned int i=0; i<sNumBlendMasks; ++i)
114                 mPriority[i] = priority;
115         }
116 
operator ==MWRender::Animation::AnimPriority117         bool operator == (const AnimPriority& other) const
118         {
119             for (unsigned int i=0; i<sNumBlendMasks; ++i)
120                 if (other.mPriority[i] != mPriority[i])
121                     return false;
122             return true;
123         }
124 
operator []MWRender::Animation::AnimPriority125         int& operator[] (BoneGroup n)
126         {
127             return mPriority[n];
128         }
129 
operator []MWRender::Animation::AnimPriority130         const int& operator[] (BoneGroup n) const
131         {
132             return mPriority[n];
133         }
134 
containsMWRender::Animation::AnimPriority135         bool contains(int priority) const
136         {
137             for (unsigned int i=0; i<sNumBlendMasks; ++i)
138                 if (priority == mPriority[i])
139                     return true;
140             return false;
141         }
142 
143         int mPriority[sNumBlendMasks];
144     };
145 
146     class TextKeyListener
147     {
148     public:
149         virtual void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key,
150                                    const SceneUtil::TextKeyMap& map) = 0;
151 
152         virtual ~TextKeyListener() = default;
153     };
154 
155     void setTextKeyListener(TextKeyListener* listener);
156 
updateCarriedLeftVisible(const int weaptype) const157     virtual bool updateCarriedLeftVisible(const int weaptype) const { return false; };
158 
159 protected:
160     class AnimationTime : public SceneUtil::ControllerSource
161     {
162     private:
163         std::shared_ptr<float> mTimePtr;
164 
165     public:
166 
setTimePtr(std::shared_ptr<float> time)167         void setTimePtr(std::shared_ptr<float> time)
168         { mTimePtr = time; }
getTimePtr() const169         std::shared_ptr<float> getTimePtr() const
170         { return mTimePtr; }
171 
172         float getValue(osg::NodeVisitor* nv) override;
173     };
174 
175     class NullAnimationTime : public SceneUtil::ControllerSource
176     {
177     public:
getValue(osg::NodeVisitor * nv)178         float getValue(osg::NodeVisitor *nv) override
179         {
180             return 0.f;
181         }
182     };
183 
184     struct AnimSource;
185 
186     struct AnimState {
187         std::shared_ptr<AnimSource> mSource;
188         float mStartTime;
189         float mLoopStartTime;
190         float mLoopStopTime;
191         float mStopTime;
192 
193         typedef std::shared_ptr<float> TimePtr;
194         TimePtr mTime;
195         float mSpeedMult;
196 
197         bool mPlaying;
198         bool mLoopingEnabled;
199         size_t mLoopCount;
200 
201         AnimPriority mPriority;
202         int mBlendMask;
203         bool mAutoDisable;
204 
AnimStateMWRender::Animation::AnimState205         AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f),
206                       mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopingEnabled(true),
207                       mLoopCount(0), mPriority(0), mBlendMask(0), mAutoDisable(true)
208         {
209         }
210         ~AnimState();
211 
getTimeMWRender::Animation::AnimState212         float getTime() const
213         {
214             return *mTime;
215         }
setTimeMWRender::Animation::AnimState216         void setTime(float time)
217         {
218             *mTime = time;
219         }
220 
shouldLoopMWRender::Animation::AnimState221         bool shouldLoop() const
222         {
223             return getTime() >= mLoopStopTime && mLoopingEnabled && mLoopCount > 0;
224         }
225     };
226     typedef std::map<std::string,AnimState> AnimStateMap;
227     AnimStateMap mStates;
228 
229     typedef std::vector<std::shared_ptr<AnimSource> > AnimSourceList;
230     AnimSourceList mAnimSources;
231 
232     osg::ref_ptr<osg::Group> mInsert;
233 
234     osg::ref_ptr<osg::Group> mObjectRoot;
235     SceneUtil::Skeleton* mSkeleton;
236 
237     // The node expected to accumulate movement during movement animations.
238     osg::ref_ptr<osg::Node> mAccumRoot;
239 
240     // The controller animating that node.
241     osg::ref_ptr<SceneUtil::KeyframeController> mAccumCtrl;
242 
243     // Used to reset the position of the accumulation root every frame - the movement should be applied to the physics system
244     osg::ref_ptr<ResetAccumRootCallback> mResetAccumRootCallback;
245 
246     // Keep track of controllers that we added to our scene graph.
247     // We may need to rebuild these controllers when the active animation groups / sources change.
248     std::vector<std::pair<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback>>> mActiveControllers;
249 
250     std::shared_ptr<AnimationTime> mAnimationTimePtr[sNumBlendMasks];
251 
252     // Stored in all lowercase for a case-insensitive lookup
253     typedef std::map<std::string, osg::ref_ptr<osg::MatrixTransform> > NodeMap;
254     mutable NodeMap mNodeMap;
255     mutable bool mNodeMapCreated;
256 
257     MWWorld::Ptr mPtr;
258 
259     Resource::ResourceSystem* mResourceSystem;
260 
261     osg::Vec3f mAccumulate;
262 
263     TextKeyListener* mTextKeyListener;
264 
265     osg::ref_ptr<RotateController> mHeadController;
266     osg::ref_ptr<RotateController> mSpineController;
267     osg::ref_ptr<RotateController> mRootController;
268     float mHeadYawRadians;
269     float mHeadPitchRadians;
270     float mUpperBodyYawRadians;
271     float mLegsYawRadians;
272     float mBodyPitchRadians;
273 
274     RotateController* addRotateController(std::string bone);
275 
276     bool mHasMagicEffects;
277 
278     osg::ref_ptr<SceneUtil::LightSource> mGlowLight;
279     osg::ref_ptr<SceneUtil::GlowUpdater> mGlowUpdater;
280     osg::ref_ptr<TransparencyUpdater> mTransparencyUpdater;
281     osg::ref_ptr<SceneUtil::LightSource> mExtraLightSource;
282 
283     float mAlpha;
284 
285     mutable std::map<std::string, float> mAnimVelocities;
286 
287     osg::ref_ptr<SceneUtil::LightListCallback> mLightListCallback;
288 
289     const NodeMap& getNodeMap() const;
290 
291     /* Sets the appropriate animations on the bone groups based on priority.
292      */
293     void resetActiveGroups();
294 
295     size_t detectBlendMask(const osg::Node* node) const;
296 
297     /* Updates the position of the accum root node for the given time, and
298      * returns the wanted movement vector from the previous time. */
299     void updatePosition(float oldtime, float newtime, osg::Vec3f& position);
300 
301     /* Resets the animation to the time of the specified start marker, without
302      * moving anything, and set the end time to the specified stop marker. If
303      * the marker is not found, or if the markers are the same, it returns
304      * false.
305      */
306     bool reset(AnimState &state, const SceneUtil::TextKeyMap &keys,
307                const std::string &groupname, const std::string &start, const std::string &stop,
308                float startpoint, bool loopfallback);
309 
310     void handleTextKey(AnimState &state, const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key,
311                        const SceneUtil::TextKeyMap& map);
312 
313     /** Sets the root model of the object.
314      *
315      * Note that you must make sure all animation sources are cleared before resetting the object
316      * root. All nodes previously retrieved with getNode will also become invalidated.
317      * @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.
318      * @param baseonly If true, then any meshes or particle systems in the model are ignored
319      *      (useful for NPCs, where only the skeleton is needed for the root, and the actual NPC parts are then assembled from separate files).
320      */
321     void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature);
322 
323     void loadAllAnimationsInFolder(const std::string &model, const std::string &baseModel);
324 
325     /** Adds the keyframe controllers in the specified model as a new animation source.
326      * @note Later added animation sources have the highest priority when it comes to finding a particular animation.
327      * @param model The file to add the keyframes for. Note that the .nif file extension will be replaced with .kf.
328      * @param baseModel The filename of the mObjectRoot, only used for error messages.
329     */
330     void addAnimSource(const std::string &model, const std::string& baseModel);
331     void addSingleAnimSource(const std::string &model, const std::string& baseModel);
332 
333     /** Adds an additional light to the given node using the specified ESM record. */
334     void addExtraLight(osg::ref_ptr<osg::Group> parent, const ESM::Light *light);
335 
336     void clearAnimSources();
337 
338     /**
339      * Provided to allow derived classes adding their own controllers. Note, the controllers must be added to mActiveControllers
340      * so they get cleaned up properly on the next controller rebuild. A controller rebuild may be necessary to ensure correct ordering.
341      */
342     virtual void addControllers();
343 
344 public:
345 
346     Animation(const MWWorld::Ptr &ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem);
347 
348     /// Must be thread safe
349     virtual ~Animation();
350 
351     MWWorld::ConstPtr getPtr() const;
352 
353     MWWorld::Ptr getPtr();
354 
355     /// Set active flag on the object skeleton, if one exists.
356     /// @see SceneUtil::Skeleton::setActive
357     /// 0 = Inactive, 1 = Active in place, 2 = Active
358     void setActive(int active);
359 
360     osg::Group* getOrCreateObjectRoot();
361 
362     osg::Group* getObjectRoot();
363 
364     /**
365      * @brief Add an effect mesh attached to a bone or the insert scene node
366      * @param model
367      * @param effectId An ID for this effect by which you can identify it later. If this is not wanted, set to -1.
368      * @param loop Loop the effect. If false, it is removed automatically after it finishes playing. If true,
369      *              you need to remove it manually using removeEffect when the effect should end.
370      * @param bonename Bone to attach to, or empty string to use the scene node instead
371      * @param texture override the texture specified in the model's materials - if empty, do not override
372      * @note Will not add an effect twice.
373      */
374     void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", const std::string& texture = "");
375     void removeEffect (int effectId);
376     void removeEffects ();
377     void getLoopingEffects (std::vector<int>& out) const;
378 
379     // Add a spell casting glow to an object. From measuring video taken from the original engine,
380     // the glow seems to be about 1.5 seconds except for telekinesis, which is 1 second.
381     void addSpellCastGlow(const ESM::MagicEffect *effect, float glowDuration = 1.5);
382 
383     virtual void updatePtr(const MWWorld::Ptr &ptr);
384 
385     bool hasAnimation(const std::string &anim) const;
386 
387     // Specifies the axis' to accumulate on. Non-accumulated axis will just
388     // move visually, but not affect the actual movement. Each x/y/z value
389     // should be on the scale of 0 to 1.
390     void setAccumulation(const osg::Vec3f& accum);
391 
392     /** Plays an animation.
393      * \param groupname Name of the animation group to play.
394      * \param priority Priority of the animation. The animation will play on
395      *                 bone groups that don't have another animation set of a
396      *                 higher priority.
397      * \param blendMask Bone groups to play the animation on.
398      * \param autodisable Automatically disable the animation when it stops
399      *                    playing.
400      * \param speedmult Speed multiplier for the animation.
401      * \param start Key marker from which to start.
402      * \param stop Key marker to stop at.
403      * \param startpoint How far in between the two markers to start. 0 starts
404      *                   at the start marker, 1 starts at the stop marker.
405      * \param loops How many times to loop the animation. This will use the
406      *              "loop start" and "loop stop" markers if they exist,
407      *              otherwise it may fall back to "start" and "stop", but only if
408      *              the \a loopFallback parameter is true.
409      * \param loopFallback Allow looping an animation that has no loop keys, i.e. fall back to use
410      *                     the "start" and "stop" keys for looping?
411      */
412     void play(const std::string &groupname, const AnimPriority& priority, int blendMask, bool autodisable,
413               float speedmult, const std::string &start, const std::string &stop,
414               float startpoint, size_t loops, bool loopfallback=false);
415 
416     /** Adjust the speed multiplier of an already playing animation.
417      */
418     void adjustSpeedMult (const std::string& groupname, float speedmult);
419 
420     /** Returns true if the named animation group is playing. */
421     bool isPlaying(const std::string &groupname) const;
422 
423     /// Returns true if no important animations are currently playing on the upper body.
424     bool upperBodyReady() const;
425 
426     /** Gets info about the given animation group.
427      * \param groupname Animation group to check.
428      * \param complete Stores completion amount (0 = at start key, 0.5 = half way between start and stop keys), etc.
429      * \param speedmult Stores the animation speed multiplier
430      * \return True if the animation is active, false otherwise.
431      */
432     bool getInfo(const std::string &groupname, float *complete=nullptr, float *speedmult=nullptr) const;
433 
434     /// Get the absolute position in the animation track of the first text key with the given group.
435     float getStartTime(const std::string &groupname) const;
436 
437     /// Get the absolute position in the animation track of the text key
438     float getTextKeyTime(const std::string &textKey) const;
439 
440     /// Get the current absolute position in the animation track for the animation that is currently playing from the given group.
441     float getCurrentTime(const std::string& groupname) const;
442 
443     size_t getCurrentLoopCount(const std::string& groupname) const;
444 
445     /** Disables the specified animation group;
446      * \param groupname Animation group to disable.
447      */
448     void disable(const std::string &groupname);
449 
450     /** Retrieves the velocity (in units per second) that the animation will move. */
451     float getVelocity(const std::string &groupname) const;
452 
453     virtual osg::Vec3f runAnimation(float duration);
454 
455     void setLoopingEnabled(const std::string &groupname, bool enabled);
456 
457     /// This is typically called as part of runAnimation, but may be called manually if needed.
458     void updateEffects();
459 
460     /// Return a node with the specified name, or nullptr if not existing.
461     /// @note The matching is case-insensitive.
462     const osg::Node* getNode(const std::string& name) const;
463 
useShieldAnimations() const464     virtual bool useShieldAnimations() const { return false; }
showWeapons(bool showWeapon)465     virtual void showWeapons(bool showWeapon) {}
getCarriedLeftShown() const466     virtual bool getCarriedLeftShown() const { return false; }
showCarriedLeft(bool show)467     virtual void showCarriedLeft(bool show) {}
setWeaponGroup(const std::string & group,bool relativeDuration)468     virtual void setWeaponGroup(const std::string& group, bool relativeDuration) {}
setVampire(bool vampire)469     virtual void setVampire(bool vampire) {}
470     /// A value < 1 makes the animation translucent, 1.f = fully opaque
471     void setAlpha(float alpha);
setPitchFactor(float factor)472     virtual void setPitchFactor(float factor) {}
attachArrow()473     virtual void attachArrow() {}
detachArrow()474     virtual void detachArrow() {}
releaseArrow(float attackStrength)475     virtual void releaseArrow(float attackStrength) {}
enableHeadAnimation(bool enable)476     virtual void enableHeadAnimation(bool enable) {}
477     // TODO: move outside of this class
478     /// Makes this object glow, by placing a Light in its center.
479     /// @param effect Controls the radius and intensity of the light.
480     virtual void setLightEffect(float effect);
481 
482     virtual void setHeadPitch(float pitchRadians);
483     virtual void setHeadYaw(float yawRadians);
484     virtual float getHeadPitch() const;
485     virtual float getHeadYaw() const;
486 
setUpperBodyYawRadians(float v)487     virtual void setUpperBodyYawRadians(float v) { mUpperBodyYawRadians = v; }
setLegsYawRadians(float v)488     virtual void setLegsYawRadians(float v) { mLegsYawRadians = v; }
getUpperBodyYawRadians() const489     virtual float getUpperBodyYawRadians() const { return mUpperBodyYawRadians; }
getLegsYawRadians() const490     virtual float getLegsYawRadians() const { return mLegsYawRadians; }
setBodyPitchRadians(float v)491     virtual void setBodyPitchRadians(float v) { mBodyPitchRadians = v; }
getBodyPitchRadians() const492     virtual float getBodyPitchRadians() const { return mBodyPitchRadians; }
493 
setAccurateAiming(bool enabled)494     virtual void setAccurateAiming(bool enabled) {}
canBeHarvested() const495     virtual bool canBeHarvested() const { return false; }
496 
497 private:
498     Animation(const Animation&);
499     void operator=(Animation&);
500 };
501 
502 class ObjectAnimation : public Animation {
503 public:
504     ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model, Resource::ResourceSystem* resourceSystem, bool animated, bool allowLight);
505 
506     bool canBeHarvested() const override;
507 };
508 
509 class UpdateVfxCallback : public osg::NodeCallback
510 {
511 public:
UpdateVfxCallback(EffectParams & params)512     UpdateVfxCallback(EffectParams& params)
513         : mFinished(false)
514         , mParams(params)
515         , mStartingTime(0)
516     {
517     }
518 
519     bool mFinished;
520     EffectParams mParams;
521 
522     void operator()(osg::Node* node, osg::NodeVisitor* nv) override;
523 
524 private:
525     double mStartingTime;
526 };
527 
528 }
529 #endif
530