PolynomialCurve.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. //
  2. // PolynomialCurve.h
  3. // cocos2d_libs
  4. //
  5. // Created by 徐俊杰 on 2020/4/24.
  6. //
  7. #ifndef PolynomialCurve_h
  8. #define PolynomialCurve_h
  9. #include "rparticle/Macros/RParticleMacros.h"
  10. NS_RRP_BEGIN
  11. template<class T>
  12. class AnimationCurveTpl;
  13. typedef AnimationCurveTpl<float> AnimationCurve;
  14. //class Vector2f;
  15. struct Polynomial
  16. {
  17. static float EvalSegment (float t, const float* coeff)
  18. {
  19. return (t * (t * (t * coeff[0] + coeff[1]) + coeff[2])) + coeff[3];
  20. }
  21. float coeff[4];
  22. };
  23. // Smaller, optimized version
  24. struct OptimizedPolynomialCurve
  25. {
  26. enum { kMaxPolynomialKeyframeCount = 3, kSegmentCount = kMaxPolynomialKeyframeCount-1, };
  27. Polynomial segments[kSegmentCount];
  28. float timeValue;
  29. float velocityValue;
  30. // Evaluate double integrated Polynomial curve.
  31. // Example: position = EvaluateDoubleIntegrated (normalizedTime) * startEnergy^2
  32. // Use DoubleIntegrate function to for example turn a force curve into a position curve.
  33. // Expects that t is in the 0...1 range.
  34. float EvaluateDoubleIntegrated (float t) const
  35. {
  36. DebugAssert(t >= -0.01F && t <= 1.01F);
  37. float res0, res1;
  38. // All segments are added together. At t = 0, the integrated curve is always zero.
  39. // 0 segment is sampled up to the 1 keyframe
  40. // First key is always assumed to be at 0 time
  41. float t1 = std::min(t, timeValue);
  42. // 1 segment is sampled from 1 key to 2 key
  43. // Last key is always assumed to be at 1 time
  44. float t2 = std::max(0.0F, t - timeValue);
  45. res0 = Polynomial::EvalSegment(t1, segments[0].coeff) * t1 * t1;
  46. res1 = Polynomial::EvalSegment(t2, segments[1].coeff) * t2 * t2;
  47. float finalResult = res0 + res1;
  48. // Add velocity of previous segments
  49. finalResult += velocityValue * std::max(t - timeValue, 0.0F);
  50. return finalResult;
  51. }
  52. // Evaluate integrated Polynomial curve.
  53. // Example: position = EvaluateIntegrated (normalizedTime) * startEnergy
  54. // Use Integrate function to for example turn a velocity curve into a position curve.
  55. // Expects that t is in the 0...1 range.
  56. float EvaluateIntegrated (float t) const
  57. {
  58. DebugAssert(t >= -0.01F && t <= 1.01F);
  59. float res0, res1;
  60. // All segments are added together. At t = 0, the integrated curve is always zero.
  61. // 0 segment is sampled up to the 1 keyframe
  62. // First key is always assumed to be at 0 time
  63. float t1 = std::min(t, timeValue);
  64. // 1 segment is sampled from 1 key to 2 key
  65. // Last key is always assumed to be at 1 time
  66. float t2 = std::max(0.0F, t - timeValue);
  67. res0 = Polynomial::EvalSegment(t1, segments[0].coeff) * t1;
  68. res1 = Polynomial::EvalSegment(t2, segments[1].coeff) * t2;
  69. return (res0 + res1);
  70. }
  71. // Evaluate the curve
  72. // extects that t is in the 0...1 range
  73. float Evaluate (float t) const
  74. {
  75. DebugAssert(t >= -0.01F && t <= 1.01F);
  76. float res0 = Polynomial::EvalSegment(t, segments[0].coeff);
  77. float res1 = Polynomial::EvalSegment(t - timeValue, segments[1].coeff);
  78. float result;
  79. if (t > timeValue)
  80. result = res1;
  81. else
  82. result = res0;
  83. return result;
  84. }
  85. // Find the maximum of a double integrated curve (x: min, y: max)
  86. Vector2f FindMinMaxDoubleIntegrated() const;
  87. // Find the maximum of the integrated curve (x: min, y: max)
  88. Vector2f FindMinMaxIntegrated() const;
  89. // Precalculates polynomials from the animation curve and a scale factor
  90. bool BuildOptimizedCurve (const AnimationCurve& editorCurve, float scale);
  91. // Integrates a velocity curve to be a position curve.
  92. // You have to call EvaluateIntegrated to evaluate the curve
  93. void Integrate ();
  94. // Integrates a velocity curve to be a position curve.
  95. // You have to call EvaluateDoubleIntegrated to evaluate the curve
  96. void DoubleIntegrate ();
  97. // Add a constant force to a velocity curve
  98. // Assumes that you have already called Integrate on the velocity curve.
  99. void AddConstantForceToVelocityCurve (float gravity)
  100. {
  101. for (int i=0;i<kSegmentCount;i++)
  102. segments[i].coeff[1] += 0.5F * gravity;
  103. }
  104. };
  105. // Bigger, not so optimized version
  106. struct PolynomialCurve
  107. {
  108. enum{ kMaxNumSegments = 8 };
  109. Polynomial segments[kMaxNumSegments]; // Cached polynomial coefficients
  110. float integrationCache[kMaxNumSegments]; // Cache of integrated values up until start of segments
  111. float doubleIntegrationCache[kMaxNumSegments]; // Cache of double integrated values up until start of segments
  112. float times[kMaxNumSegments]; // Time value for end of segment
  113. int segmentCount;
  114. // Find the maximum of a double integrated curve (x: min, y: max)
  115. Vector2f FindMinMaxDoubleIntegrated() const;
  116. // Find the maximum of the integrated curve (x: min, y: max)
  117. Vector2f FindMinMaxIntegrated() const;
  118. // Precalculates polynomials from the animation curve and a scale factor
  119. bool BuildCurve(const AnimationCurve& editorCurve, float scale);
  120. // Integrates a velocity curve to be a position curve.
  121. // You have to call EvaluateIntegrated to evaluate the curve
  122. void Integrate ();
  123. // Integrates a velocity curve to be a position curve.
  124. // You have to call EvaluateDoubleIntegrated to evaluate the curve
  125. void DoubleIntegrate ();
  126. // Evaluates if it is possible to represent animation curve as PolynomialCurve
  127. static bool IsValidCurve(const AnimationCurve& editorCurve);
  128. // Evaluate double integrated Polynomial curve.
  129. // Example: position = EvaluateDoubleIntegrated (normalizedTime) * startEnergy^2
  130. // Use DoubleIntegrate function to for example turn a force curve into a position curve.
  131. // Expects that t is in the 0...1 range.
  132. float EvaluateDoubleIntegrated (float t) const
  133. {
  134. DebugAssert(t >= -0.01F && t <= 1.01F);
  135. float prevTimeValue = 0.0f;
  136. for(int i = 0; i < segmentCount; i++)
  137. {
  138. if(t <= times[i])
  139. {
  140. const float time = t - prevTimeValue;
  141. return doubleIntegrationCache[i] + integrationCache[i] * time + Polynomial::EvalSegment(time, segments[i].coeff) * time * time;
  142. }
  143. prevTimeValue = times[i];
  144. }
  145. DebugAssert(!"PolyCurve: Outside segment range!");
  146. return 1.0f;
  147. }
  148. // Evaluate integrated Polynomial curve.
  149. // Example: position = EvaluateIntegrated (normalizedTime) * startEnergy
  150. // Use Integrate function to for example turn a velocity curve into a position curve.
  151. // Expects that t is in the 0...1 range.
  152. float EvaluateIntegrated (float t) const
  153. {
  154. DebugAssert(t >= -0.01F && t <= 1.01F);
  155. float prevTimeValue = 0.0f;
  156. for(int i = 0; i < segmentCount; i++)
  157. {
  158. if(t <= times[i])
  159. {
  160. const float time = t - prevTimeValue;
  161. return integrationCache[i] + Polynomial::EvalSegment(time, segments[i].coeff) * time;
  162. }
  163. prevTimeValue = times[i];
  164. }
  165. DebugAssert(!"PolyCurve: Outside segment range!");
  166. return 1.0f;
  167. }
  168. // Evaluate the curve
  169. // extects that t is in the 0...1 range
  170. float Evaluate(float t) const
  171. {
  172. DebugAssert(t >= -0.01F && t <= 1.01F);
  173. float prevTimeValue = 0.0f;
  174. for(int i = 0; i < segmentCount; i++)
  175. {
  176. if(t <= times[i])
  177. return Polynomial::EvalSegment(t - prevTimeValue, segments[i].coeff);
  178. prevTimeValue = times[i];
  179. }
  180. DebugAssert(!"PolyCurve: Outside segment range!");
  181. return 1.0f;
  182. }
  183. };
  184. void SetPolynomialCurveToValue (AnimationCurve& a, OptimizedPolynomialCurve& c, float value);
  185. void SetPolynomialCurveToLinear (AnimationCurve& a, OptimizedPolynomialCurve& c);
  186. void ConstrainToPolynomialCurve (AnimationCurve& curve);
  187. bool IsValidPolynomialCurve (const AnimationCurve& curve);
  188. void CalculateMinMax(Vector2f& minmax, float value);
  189. NS_RRP_END
  190. #endif /* PolynomialCurve_h */