BabylonAnimation.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #pragma once
  2. #include <string>
  3. #include <vector>
  4. #include "BabylonVertex.h"
  5. #include <cpprest\json.h>
  6. // base class representing babylon animations
  7. class BabylonAnimationBase
  8. {
  9. public:
  10. static const int dataType_Float = 0;
  11. static const int dataType_Vector3 = 1;
  12. static const int dataType_Quaternion = 2;
  13. static const int dataType_Matrix = 3;
  14. static const int loopBehavior_Relative = 0;
  15. static const int loopBehavior_Cycle = 1;
  16. static const int loopBehavior_Constant = 2;
  17. int dataType;
  18. int loopBehavior;
  19. int framePerSecond;
  20. std::wstring name;
  21. std::wstring property;
  22. bool autoAnimate;
  23. int autoAnimateFrom;
  24. int autoAnimateTo;
  25. bool autoAnimateLoop;
  26. BabylonAnimationBase(int loopBehavior, int fps, const std::wstring& name, const std::wstring& animatedProperty, bool autoAnimate, int autoAnimateFrom, int autoAnimateTo, bool autoAnimateLoop);
  27. virtual ~BabylonAnimationBase(){}
  28. virtual bool isConstant() = 0;
  29. virtual web::json::value toJson() const = 0;
  30. };
  31. // key frame data
  32. template<typename T>
  33. struct babylon_animation_key{
  34. int frame;
  35. T values;
  36. };
  37. // traits for animated babylon data types (must contain :
  38. // static const int dataType
  39. // static web::json::value jsonify(const T& value)
  40. template<typename T>
  41. struct bab_anim_traits{
  42. };
  43. // specialization for vectors 3D
  44. template<>
  45. struct bab_anim_traits < babylon_vector3 >
  46. {
  47. static const int dataType = BabylonAnimationBase::dataType_Vector3;
  48. static web::json::value jsonify(const babylon_vector3& value){
  49. auto jarray = web::json::value::array();
  50. jarray[0] = web::json::value::number(value.x);
  51. jarray[1] = web::json::value::number(value.y);
  52. jarray[2] = web::json::value::number(value.z);
  53. return jarray;
  54. }
  55. };
  56. // specialization for quaternions
  57. template<>
  58. struct bab_anim_traits < babylon_vector4 >
  59. {
  60. static const int dataType = BabylonAnimationBase::dataType_Quaternion;
  61. static web::json::value jsonify(const babylon_vector4& value){
  62. auto jarray = web::json::value::array();
  63. jarray[0] = web::json::value::number(value.x);
  64. jarray[1] = web::json::value::number(value.y);
  65. jarray[2] = web::json::value::number(value.z);
  66. jarray[3] = web::json::value::number(value.w);
  67. return jarray;
  68. }
  69. };
  70. // specialization for matrices
  71. template<>
  72. struct bab_anim_traits < FbxMatrix >
  73. {
  74. static const int dataType = BabylonAnimationBase::dataType_Matrix;
  75. static web::json::value jsonify(const FbxMatrix& value){
  76. auto jmat = web::json::value::array();
  77. for (auto x = 0; x < 4; ++x){
  78. for (auto y = 0; y < 4; ++y){
  79. jmat[x * 4 + y] = web::json::value::number(value[x][y]);
  80. }
  81. }
  82. return jmat;
  83. }
  84. };
  85. // specialization for scalar floats
  86. template<>
  87. struct bab_anim_traits < float >
  88. {
  89. static const int dataType = BabylonAnimationBase::dataType_Float;
  90. static web::json::value jsonify(float value){
  91. auto jarray = web::json::value::array();
  92. jarray[0] = web::json::value::number(value);
  93. return jarray;
  94. }
  95. };
  96. // used for interpolation simplification
  97. template<typename T>
  98. bool isNear(const T& lhs, const T& rhs);
  99. template <>
  100. inline bool isNear<float>(const float& lhs, const float& rhs){
  101. auto diff = lhs - rhs;
  102. return diff >= -0.000001f && diff <= 0.000001f;
  103. }
  104. template <>
  105. inline bool isNear<FbxMatrix>(const FbxMatrix& lhs, const FbxMatrix& rhs){
  106. return lhs == rhs;
  107. }
  108. template <>
  109. inline bool isNear<babylon_vector3>(const babylon_vector3& lhs, const babylon_vector3& rhs){
  110. return isNear(lhs.x, rhs.x)
  111. && isNear(lhs.y, rhs.y)
  112. && isNear(lhs.z, rhs.z);
  113. }
  114. template <>
  115. inline bool isNear<babylon_vector4>(const babylon_vector4& lhs, const babylon_vector4& rhs){
  116. return isNear(lhs.x, rhs.x)
  117. && isNear(lhs.y, rhs.y)
  118. && isNear(lhs.z, rhs.z)
  119. && isNear(lhs.w, rhs.w);
  120. }
  121. template<typename T>
  122. inline T lerp(const T& start, const T& end, float factor){
  123. return start + (end - start)*factor;
  124. }
  125. template<typename T>
  126. bool isLinearInterpolation(const babylon_animation_key<T>& key0, const babylon_animation_key<T>& key1, const babylon_animation_key<T>& key2){
  127. auto testVal = lerp(key0.values, key2.values, static_cast<float>(key1.frame - key0.frame) / static_cast<float>(key2.frame - key0.frame));
  128. return isNear(testVal, key1.values);
  129. }
  130. // typed babylon animation.
  131. // requires bab_anim_traits<T>, isNear<T> and basic arithmetic operators
  132. template<typename T>
  133. class BabylonAnimation : public BabylonAnimationBase
  134. {
  135. public:
  136. std::vector<babylon_animation_key<T>> keys;
  137. BabylonAnimation(int loopBehavior, int fps, const std::wstring& name, const std::wstring& animatedProperty, bool autoAnimate, int autoAnimateFrom, int autoAnimateTo, bool autoAnimateLoop) :
  138. BabylonAnimationBase(loopBehavior, fps, name, animatedProperty, autoAnimate, autoAnimateFrom, autoAnimateTo, autoAnimateLoop)
  139. {
  140. dataType = bab_anim_traits<T>::dataType;
  141. }
  142. void appendKey(const babylon_animation_key<T>& key){
  143. if (keys.size() <= 1){
  144. // nothing to simplify
  145. keys.push_back(key);
  146. }
  147. else{
  148. if (isNear(key.values, keys[keys.size() - 1].values) && isNear(key.values, keys[keys.size() - 2].values)){
  149. // if 3 times the same value, eliminate intermediate key
  150. keys.resize(keys.size() - 1);
  151. keys.push_back(key);
  152. }
  153. else if (isLinearInterpolation(keys[keys.size() - 2], keys[keys.size() - 1], key)){
  154. // if the 3 last values are linearly interpolated, eliminate the intermediate key
  155. keys.resize(keys.size() - 1);
  156. keys.push_back(key);
  157. }
  158. else{
  159. keys.push_back(key);
  160. }
  161. }
  162. }
  163. virtual bool isConstant() override{
  164. if (keys.size() < 2){
  165. return true;
  166. }
  167. if (keys.size() > 2){
  168. return false;
  169. }
  170. return isNear(keys[0].values, keys[1].values);
  171. }
  172. virtual web::json::value toJson() const override {
  173. auto jobj = web::json::value::object();
  174. jobj[L"dataType"] = web::json::value::number(dataType);
  175. jobj[L"framePerSecond"] = web::json::value::number(framePerSecond);
  176. jobj[L"loopBehavior"] = web::json::value::number(loopBehavior);
  177. jobj[L"name"] = web::json::value::string(name);
  178. jobj[L"property"] = web::json::value::string(property);
  179. jobj[L"autoAnimate"] = web::json::value::boolean(autoAnimate);
  180. jobj[L"autoAnimateFrom"] = web::json::value::number(autoAnimateFrom);
  181. jobj[L"autoAnimateTo"] = web::json::value::number(autoAnimateTo);
  182. jobj[L"autoAnimateLoop"] = web::json::value::boolean(autoAnimateLoop);
  183. auto jkeys = web::json::value::array();
  184. for (auto ix = 0u; ix < keys.size(); ++ix){
  185. auto jkey = web::json::value::object();
  186. jkey[L"frame"] = keys[ix].frame;
  187. jkey[L"values"] = bab_anim_traits<T>::jsonify(keys[ix].values);
  188. jkeys[jkeys.size()] = jkey;
  189. }
  190. jobj[L"keys"] = jkeys;
  191. return jobj;
  192. }
  193. };