OpenMW
|
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