OpenMW
apps/openmw/mwrender/animation.hpp
Go to the documentation of this file.
00001 #ifndef _GAME_RENDER_ANIMATION_H
00002 #define _GAME_RENDER_ANIMATION_H
00003 
00004 #include <OgreController.h>
00005 #include <OgreVector3.h>
00006 
00007 #include <components/nifogre/ogrenifloader.hpp>
00008 
00009 #include "../mwworld/ptr.hpp"
00010 
00011 
00012 namespace MWRender
00013 {
00014 class Camera;
00015 
00016 class Animation
00017 {
00018 public:
00019     enum Group {
00020         Group_LowerBody = 1<<0,
00021 
00022         Group_Torso = 1<<1,
00023         Group_LeftArm = 1<<2,
00024         Group_RightArm = 1<<3,
00025 
00026         Group_UpperBody = Group_Torso | Group_LeftArm | Group_RightArm,
00027 
00028         Group_All = Group_LowerBody | Group_UpperBody
00029     };
00030 
00031 protected:
00032     /* This is the number of *discrete* groups. */
00033     static const size_t sNumGroups = 4;
00034 
00035     class AnimationValue : public Ogre::ControllerValue<Ogre::Real>
00036     {
00037     private:
00038         Animation *mAnimation;
00039         std::string mAnimationName;
00040 
00041     public:
00042         AnimationValue(Animation *anim)
00043           : mAnimation(anim)
00044         { }
00045 
00046         void setAnimName(const std::string &name)
00047         { mAnimationName = name; }
00048         const std::string &getAnimName() const
00049         { return mAnimationName; }
00050 
00051         virtual Ogre::Real getValue() const;
00052         virtual void setValue(Ogre::Real value);
00053     };
00054 
00055     class EffectAnimationValue : public Ogre::ControllerValue<Ogre::Real>
00056     {
00057     private:
00058         float mTime;
00059     public:
00060         EffectAnimationValue() : mTime(0) {  }
00061         void addTime(float time) { mTime += time; }
00062         void resetTime(float value) { mTime = value; }
00063 
00064         virtual Ogre::Real getValue() const;
00065         virtual void setValue(Ogre::Real value);
00066     };
00067 
00068 
00069 
00070     class NullAnimationValue : public Ogre::ControllerValue<Ogre::Real>
00071     {
00072     public:
00073         virtual Ogre::Real getValue() const
00074         { return 0.0f; }
00075         virtual void setValue(Ogre::Real value)
00076         { }
00077     };
00078 
00079 
00080     struct AnimSource : public Ogre::AnimationAlloc {
00081         NifOgre::TextKeyMap mTextKeys;
00082         std::vector<Ogre::Controller<Ogre::Real> > mControllers[sNumGroups];
00083     };
00084     typedef std::vector< Ogre::SharedPtr<AnimSource> > AnimSourceList;
00085 
00086     struct AnimState {
00087         Ogre::SharedPtr<AnimSource> mSource;
00088         float mStartTime;
00089         float mLoopStartTime;
00090         float mLoopStopTime;
00091         float mStopTime;
00092 
00093         float mTime;
00094         float mSpeedMult;
00095 
00096         bool mPlaying;
00097         size_t mLoopCount;
00098 
00099         int mPriority;
00100         int mGroups;
00101         bool mAutoDisable;
00102 
00103         AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f),
00104                       mTime(0.0f), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0),
00105                       mPriority(0), mGroups(0), mAutoDisable(true)
00106         { }
00107     };
00108     typedef std::map<std::string,AnimState> AnimStateMap;
00109 
00110     typedef std::map<Ogre::MovableObject*,std::string> ObjectAttachMap;
00111 
00112     struct EffectParams
00113     {
00114         std::string mModelName; // Just here so we don't add the same effect twice
00115         NifOgre::ObjectScenePtr mObjects;
00116         int mEffectId;
00117         bool mLoop;
00118         std::string mBoneName;
00119     };
00120 
00121     std::vector<EffectParams> mEffects;
00122 
00123     MWWorld::Ptr mPtr;
00124     Camera *mCamera;
00125 
00126     Ogre::SceneNode *mInsert;
00127     Ogre::Entity *mSkelBase;
00128     NifOgre::ObjectScenePtr mObjectRoot;
00129     AnimSourceList mAnimSources;
00130     Ogre::Node *mAccumRoot;
00131     Ogre::Node *mNonAccumRoot;
00132     NifOgre::NodeTargetValue<Ogre::Real> *mNonAccumCtrl;
00133     Ogre::Vector3 mAccumulate;
00134 
00135     AnimStateMap mStates;
00136 
00137     Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
00138     Ogre::SharedPtr<NullAnimationValue> mNullAnimationValuePtr;
00139 
00140     ObjectAttachMap mAttachedObjects;
00141 
00142 
00143     /* Sets the appropriate animations on the bone groups based on priority.
00144      */
00145     void resetActiveGroups();
00146 
00147     static size_t detectAnimGroup(const Ogre::Node *node);
00148 
00149     static float calcAnimVelocity(const NifOgre::TextKeyMap &keys,
00150                                   NifOgre::NodeTargetValue<Ogre::Real> *nonaccumctrl,
00151                                   const Ogre::Vector3 &accum,
00152                                   const std::string &groupname);
00153 
00154     /* Updates a skeleton instance so that all bones matching the source skeleton (based on
00155      * bone names) are positioned identically. */
00156     void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel);
00157 
00158     /* Updates the position of the accum root node for the given time, and
00159      * returns the wanted movement vector from the previous time. */
00160     void updatePosition(float oldtime, float newtime, Ogre::Vector3 &position);
00161 
00162     static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname);
00163 
00164     /* Resets the animation to the time of the specified start marker, without
00165      * moving anything, and set the end time to the specified stop marker. If
00166      * the marker is not found, or if the markers are the same, it returns
00167      * false.
00168      */
00169     bool reset(AnimState &state, const NifOgre::TextKeyMap &keys,
00170                const std::string &groupname, const std::string &start, const std::string &stop,
00171                float startpoint);
00172 
00173     void handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key);
00174 
00175     /* Sets the root model of the object. If 'baseonly' is true, then any meshes or particle
00176      * systems in the model are ignored (useful for NPCs, where only the skeleton is needed for
00177      * the root).
00178      *
00179      * Note that you must make sure all animation sources are cleared before reseting the object
00180      * root. All nodes previously retrieved with getNode will also become invalidated.
00181      */
00182     void setObjectRoot(const std::string &model, bool baseonly);
00183 
00184     /* Adds the keyframe controllers in the specified model as a new animation source. Note that
00185      * the filename portion of the provided model name will be prepended with 'x', and the .nif
00186      * extension will be replaced with .kf. */
00187     void addAnimSource(const std::string &model);
00188 
00190     void addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScenePtr objlist, const ESM::Light *light);
00191 
00192     static void setRenderProperties(NifOgre::ObjectScenePtr objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue,
00193                                     Ogre::uint8 transqueue, Ogre::Real dist=0.0f,
00194                                     bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL);
00195 
00196     void clearAnimSources();
00197 
00198     // TODO: Should not be here
00199     Ogre::Vector3 getEnchantmentColor(MWWorld::Ptr item);
00200 
00201 public:
00202     Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node);
00203     virtual ~Animation();
00204 
00215     void addEffect (const std::string& model, int effectId, bool loop = false, const std::string& bonename = "", std::string texture = "");
00216     void removeEffect (int effectId);
00217     void getLoopingEffects (std::vector<int>& out);
00218 
00220     virtual void preRender (Ogre::Camera* camera);
00221 
00222     virtual void setAlpha(float alpha) {}
00223 private:
00224     void updateEffects(float duration);
00225 
00226 
00227 public:
00228     void updatePtr(const MWWorld::Ptr &ptr);
00229 
00230     bool hasAnimation(const std::string &anim);
00231 
00232     // Specifies the axis' to accumulate on. Non-accumulated axis will just
00233     // move visually, but not affect the actual movement. Each x/y/z value
00234     // should be on the scale of 0 to 1.
00235     void setAccumulation(const Ogre::Vector3 &accum);
00236 
00254     void play(const std::string &groupname, int priority, int groups, bool autodisable,
00255               float speedmult, const std::string &start, const std::string &stop,
00256               float startpoint, size_t loops);
00257 
00259     bool isPlaying(const std::string &groupname) const;
00260 
00261     bool isPlaying(Group group) const;
00262 
00269     bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL) const;
00270 
00274     void disable(const std::string &groupname);
00275 
00277     float getVelocity(const std::string &groupname) const;
00278 
00279     virtual Ogre::Vector3 runAnimation(float duration);
00280 
00281     virtual void showWeapons(bool showWeapon);
00282     virtual void showCarriedLeft(bool show) {}
00283 
00284     void enableLights(bool enable);
00285 
00286     Ogre::AxisAlignedBox getWorldBounds();
00287 
00288     void setCamera(Camera *cam)
00289     { mCamera = cam; }
00290 
00291     Ogre::Node *getNode(const std::string &name);
00292 
00293     // Attaches the given object to a bone on this object's base skeleton. If the bone doesn't
00294     // exist, the object isn't attached and NULL is returned. The returned TagPoint is only
00295     // valid until the next setObjectRoot call.
00296     Ogre::TagPoint *attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj);
00297     void detachObjectFromBone(Ogre::MovableObject *obj);
00298 };
00299 
00300 class ObjectAnimation : public Animation {
00301 public:
00302     ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model);
00303 
00304     void addLight(const ESM::Light *light);
00305 
00306     bool canBatch() const;
00307     void fillBatch(Ogre::StaticGeometry *sg);
00308 };
00309 
00310 }
00311 #endif