Animation.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /******************************************************************************
  2. Use 'AnimBone' to store animation keys for a particular bone.
  3. Use 'AnimEvent' to store information about a custom event in the animation at a custom time moment.
  4. Use 'Animation' to store body animation keys, animation keys for multiple bones, and events.
  5. Use 'SkelAnim' to handle the relation between a skeleton and an animation.
  6. /******************************************************************************/
  7. STRUCT2(AnimBone , AnimKeys, BoneID) // Animation Bone - set of animation keyframes for a particular bone
  8. //{
  9. void save(TextNode &node)C; // save as text
  10. };
  11. /******************************************************************************/
  12. struct AnimEvent // Animation Event - custom event which occurs at 'time' in 'Animation'
  13. {
  14. Char8 name[32]; // name of the event
  15. Flt time ; // time position when the event occurs
  16. AnimEvent& set(C Str8 &name, Flt time) {Set(T.name, name); T.time=time; return T;}
  17. void save(TextNode &node)C; // save as text
  18. AnimEvent() {name[0]=0; time=0;}
  19. };
  20. /******************************************************************************/
  21. enum ANIM_FLAG // Animation Flags
  22. {
  23. ANIM_LINEAR=0x1, // linear (without smoothing)
  24. ANIM_LOOP =0x2, // looped
  25. };
  26. enum ROOT_FLAG // Root Flags
  27. {
  28. ROOT_BONE_POSITION =1<<0, // set root animation position from bone position (valid only when converting bone to root, ignored if root already available)
  29. ROOT_2_KEYS =1<<1, // reduce root animation to 2 keyframes: start+end
  30. ROOT_START_IDENTITY=1<<2, // start root animation with identity
  31. ROOT_DEL_POSITION_X=1<<3, // remove root animation position X
  32. ROOT_DEL_POSITION_Y=1<<4, // remove root animation position Y
  33. ROOT_DEL_POSITION_Z=1<<5, // remove root animation position Z
  34. ROOT_DEL_ROTATION_X=1<<6, // remove root animation rotation X
  35. ROOT_DEL_ROTATION_Y=1<<7, // remove root animation rotation Y
  36. ROOT_DEL_ROTATION_Z=1<<8, // remove root animation rotation Z
  37. ROOT_DEL_SCALE =1<<9, // remove root animation scale
  38. ROOT_DEL_POSITION=ROOT_DEL_POSITION_X|ROOT_DEL_POSITION_Y|ROOT_DEL_POSITION_Z,
  39. ROOT_DEL_ROTATION=ROOT_DEL_ROTATION_X|ROOT_DEL_ROTATION_Y|ROOT_DEL_ROTATION_Z,
  40. ROOT_DEL =ROOT_DEL_POSITION|ROOT_DEL_ROTATION|ROOT_DEL_SCALE,
  41. };
  42. /******************************************************************************/
  43. struct Animation // set of animation keyframes used for animating 'AnimatedSkeleton'
  44. {
  45. Mems<AnimBone> bones ; // bone animations
  46. Mems<AnimEvent> events; // animation events
  47. AnimKeys keys ; // animation keys of the whole body
  48. // get / set
  49. Bool is()C {return bones.elms() || events.elms() || keys.is();} // if has any data
  50. Int findBoneI(CChar8 *name, BONE_TYPE type=BONE_UNKNOWN, Int type_index=0, Int type_sub=0)C; // find bone animation index, bones are first compared against the specified 'name', if there's no exact match and the 'type' is specified (not BONE_UNKNOWN) then type parameters are used for searching, -1 on fail
  51. AnimBone* findBone (CChar8 *name, BONE_TYPE type=BONE_UNKNOWN, Int type_index=0, Int type_sub=0) ; // find bone animation , bones are first compared against the specified 'name', if there's no exact match and the 'type' is specified (not BONE_UNKNOWN) then type parameters are used for searching, null on fail
  52. C AnimBone* findBone (CChar8 *name, BONE_TYPE type=BONE_UNKNOWN, Int type_index=0, Int type_sub=0)C; // find bone animation , bones are first compared against the specified 'name', if there's no exact match and the 'type' is specified (not BONE_UNKNOWN) then type parameters are used for searching, null on fail
  53. AnimBone& getBone (CChar8 *name, BONE_TYPE type=BONE_UNKNOWN, Int type_index=0, Int type_sub=0) ; // get bone animation , bones are first compared against the specified 'name', if there's no exact match and the 'type' is specified (not BONE_UNKNOWN) then type parameters are used for searching, creates new bone animation if not found
  54. Animation& loop (Bool loop ); Bool loop ()C {return FlagTest(_flag, ANIM_LOOP );} // set/get looping
  55. Animation& linear(Bool linear ); Bool linear()C {return FlagTest(_flag, ANIM_LINEAR);} // set/get linear smoothing (setting linear smoothing makes the animation look more mechanized)
  56. Animation& length(Flt length, Bool rescale_keyframes); Flt length()C {return _length ;} // set/get animation length, 'rescale_keyframes'=if proportionally rescale keyframes from current length to new length
  57. AnimEvent* findEvent(CChar8 *name) ; // find animation event, null if not found
  58. C AnimEvent* findEvent(CChar8 *name)C; // find animation event, null if not found
  59. Int eventCount(CChar8 *name)C; // get number of events with specified name in this animation
  60. Bool eventAfter (CChar8 *name , Flt time )C; // if after 'name' event , 'time'=animation time
  61. Bool eventOccurred(CChar8 *name , Flt start_time, Flt dt)C; // if 'name' event occurred , 'start_time'=animation time at the start of the frame, 'dt'=animation time delta (should be set to "Time.d() * animation_speed")
  62. Bool eventBetween (CChar8 *from, CChar8 *to, Flt start_time, Flt dt)C; // if between events 'from' and 'to', 'start_time'=animation time at the start of the frame, 'dt'=animation time delta (should be set to "Time.d() * animation_speed")
  63. Flt eventProgress(CChar8 *from, CChar8 *to, Flt time )C; // get progress between events 'from' and 'to', 'time'=animation time, 0 on fail
  64. void getRootMatrix ( Matrix &matrix , Flt time )C; // get root 'matrix' at specified 'time'
  65. void getRootMatrixCumulative( Matrix &matrix , Flt time )C; // get root 'matrix' at specified 'time' with accumulation enabled for looped animations
  66. void getRootTransform (RevMatrix &transform, Flt start_time, Flt end_time)C; // get matrix that transforms root from 'start_time' to 'end_time'
  67. C Matrix& rootStart ()C {return _root_start ;} // get root matrix at the start of animation
  68. C Matrix& rootEnd ()C {return _root_end ;} // get root matrix at the end of animation
  69. C RevMatrix& rootTransform()C {return _root_transform;} // get matrix that transforms 'rootStart' into 'rootEnd'
  70. Flt rootSpeed ()C {return _root_transform.pos.length ()/ _length ;} // get root movement speed between first and last keyframe
  71. Flt rootSpeed2()C {return _root_transform.pos.length2()/Sqr(_length);} // get root movement speed squared between first and last keyframe
  72. Flt rootSpeedZ()C {return _root_transform.pos.z / _length ;} // get root Z movement speed between first and last keyframe
  73. // transform
  74. Animation& transform(C Matrix &matrix, C Skeleton &source); // transform animation by 'matrix', basing on 'source' skeleton
  75. Animation& mirror ( C Skeleton &source); // mirror animation in X axis , basing on 'source' skeleton
  76. // operations
  77. Animation& setTangents (); // recalculate tangents , this needs to be called after manually modifying the keyframes
  78. Animation& setRootMatrix(); // recalculate root matrixes, this needs to be called after manually modifying the keyframes
  79. Animation& optimize(Flt angle_eps=EPS_ANIM_ANGLE, Flt pos_eps=EPS_ANIM_POS, Flt scale_eps=EPS_ANIM_SCALE, Bool remove_unused_bones=true); // optimize animation by removing similar keyframes, 'angle_eps'=angular epsilon 0..PI, 'pos_eps'=position epsilon 0..Inf, 'scale_eps'=scale epsilon 0..Inf, 'remove_unused_bones'=if remove unused bones after performing key reduction
  80. Animation& clip (Flt start_time, Flt end_time, Bool remove_unused_bones=true); // clip animation to 'start_time' .. 'end_time', this will remove all keyframes which aren't located in selected range
  81. Animation& clipAuto (); // clip animation range starting with first keyframe and ending with last keyframe
  82. Animation& maximizeLength(); // maximize animation length based on maximum time value out of all keyframes and events
  83. Animation& slideTime (Flt dt); // slide time positions of keyframes
  84. Animation& scaleTime (Flt start_time, Flt end_time, Flt scale); // scale time positions of keyframes that are between 'start_time' and 'end_time' by 'scale' factor
  85. Animation& adjustForSameSkeletonWithDifferentPose (C Skeleton &source, C Skeleton &target ); // adjust animation which was created for 'source' skeleton to be used for 'target' skeleton
  86. Animation& adjustForSameTransformWithDifferentSkeleton(C Skeleton &source, C Skeleton &target, Int source_bone_as_root=-1, C MemPtr< Mems<IndexWeight> > &weights=null, UInt root_flags=0); // adjust animation which was created for 'source' skeleton to be used for 'target' skeleton, 'source_bone_as_root'=index of a bone in 'source' skeleton that is converted to root, 'root_flags'=ROOT_FLAG, it's recommended to call 'optimize' after this method, because it may generate a lot of unnecessary keyframes
  87. Animation& offsetRootBones(C Skeleton &skeleton, C Vec &move); // offset all bones that have no parents by 'move' movement in global space
  88. Animation& setBoneTypeIndexesFromSkeleton (C Skeleton &skeleton); // set bone animation type and indexes from 'skeleton' according to bone animation name
  89. Bool setBoneNameTypeIndexesFromSkeleton(C Skeleton &skeleton); // set bone animation name type and indexes from 'skeleton' according to bone animation info, returns true if any change was made
  90. Animation& reverse(); // reverse animation
  91. #if EE_PRIVATE
  92. void setRootMatrix2();
  93. void getRootMatrixExactTime(Matrix &matrix, Flt time)C; // get root 'matrix' at specified 'time'
  94. Bool timeRange(Flt &min, Flt &max)C; // get min/max time value out of all keyframes/events, false on fail (if there are no keyframes/events)
  95. Animation& sortFrames(); // sort frames in time order, this should be called after manually modifying the keyframes and changing their time positions
  96. Animation& removeUnused(); // remove unused bone animations
  97. void includeTimesForBoneAndItsParents(C Skeleton &skel, Int skel_bone, MemPtr<Flt, 16384> orn_times, MemPtr<Flt, 16384> pos_times, MemPtr<Flt, 16384> scale_times)C;
  98. Animation& copyParams(C Animation &src);
  99. // transform
  100. Animation& scale (Flt scale ); // scale position offset key values by 'scale'
  101. Animation& mirrorX ( ); // mirror keyframes in x axis
  102. Animation& rightToLeft(C Skeleton &source); // convert from right hand to left hand coordinate system, basing on 'source' skeleton and 'mesh' source mesh
  103. // convert
  104. Animation& convertRotToOrn(C Skeleton &skeleton); // convert relative rotations to target orientations according to given 'skeleton'
  105. Animation& convertOrnToRot(C Skeleton &skeleton); // convert target orientations to relative rotations according to given 'skeleton'
  106. #endif
  107. void freezeBone(C Skeleton &skel, Int skel_bone); // adjust the animation by moving root bones, so that selected bone will appear without movement
  108. // io
  109. void operator=(C Str &name) ; // load, Exit on fail
  110. void operator=(C UID &id ) ; // load, Exit on fail
  111. Bool save (C Str &name)C; // save, false on fail
  112. Bool load (C Str &name) ; // load, false on fail
  113. Bool save(File &f)C; // save, false on fail
  114. Bool load(File &f) ; // load, false on fail
  115. void save(MemPtr<TextNode> nodes)C; // save as text
  116. Animation& del(); // delete manually
  117. Animation();
  118. private:
  119. Byte _flag;
  120. Flt _length;
  121. Matrix _root_start, _root_end, _root_start_inv;
  122. RevMatrix _root_transform;
  123. #if EE_PRIVATE
  124. void zero();
  125. #endif
  126. };
  127. /******************************************************************************/
  128. extern Cache<Animation> Animations; // Animation Cache
  129. /******************************************************************************/
  130. struct SkelAnim // helper class for 'Skeleton' <-> 'Animation' relation, 'SkelAnim' objects are by default obtained by 'AnimatedSkeleton.findSkelAnim' and 'AnimatedSkeleton.getSkelAnim'
  131. {
  132. // manage
  133. SkelAnim& create(C Skeleton &skeleton, C Animation &animation); // create object to be used for 'skeleton' and 'animation' pair, 'animation' must point to constant memory address (only pointer to it is stored through which the object can be later accessed)
  134. // get
  135. CChar* name ()C {return Animations.name(_animation );} // get animation name
  136. UID id ()C {return Animations.id (_animation );} // get animation name ID
  137. C Animation* animation()C {return _animation ;} // get animation object
  138. Flt length ()C {return _animation ? _animation->length() : 0;} // get animation length
  139. Int eventCount(CChar8 *name)C {return _animation ? _animation->eventCount(name) : 0;} // get number of events with specified name in this animation
  140. Bool eventAfter (CChar8 *name , Flt time )C {return _animation ? _animation->eventAfter (name , time ) : false;} // if after 'name' event , 'time'=animation time
  141. Bool eventOccurred(CChar8 *name , Flt start_time, Flt dt)C {return _animation ? _animation->eventOccurred(name , start_time, dt) : false;} // if 'name' event occurred , 'start_time'=animation time at the start of the frame, 'dt'=animation time delta (should be set to "Time.d() * animation_speed")
  142. Bool eventBetween (CChar8 *from, CChar8 *to, Flt start_time, Flt dt)C {return _animation ? _animation->eventBetween (from, to, start_time, dt) : false;} // if between events 'from' and 'to', 'start_time'=animation time at the start of the frame, 'dt'=animation time delta (should be set to "Time.d() * animation_speed")
  143. Flt eventProgress(CChar8 *from, CChar8 *to, Flt time )C {return _animation ? _animation->eventProgress(from, to, time ) : 0;} // get progress between events 'from' and 'to', 'time'=animation time, 0 on fail
  144. #if EE_PRIVATE
  145. Byte abonToSbon(Byte abon)C {return _bone[abon];} // convert 'AnimBone' to 'SkelBone' index, 0xFF on fail
  146. Int sbonToAbon(Int sbon)C; // convert 'SkelBone' to 'AnimBone' index, -1 on fail
  147. Bool load(C Str &name ) {return false;} // this is unused, 'load' with 'user' is used instead
  148. Bool load(C Str &name, Ptr user);
  149. void zero();
  150. #endif
  151. SkelAnim& del(); // delete manually
  152. ~SkelAnim() {del();}
  153. SkelAnim();
  154. explicit SkelAnim(C Skeleton &skeleton, C Animation &animation);
  155. SkelAnim(C SkelAnim &src);
  156. void operator=(C SkelAnim &src);
  157. private:
  158. Byte *_bone;
  159. C Animation *_animation;
  160. };
  161. /******************************************************************************/
  162. #if EE_PRIVATE
  163. void ShutAnimation();
  164. #endif
  165. /******************************************************************************/