123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- //
- // PolynomialCurve.h
- // cocos2d_libs
- //
- // Created by 徐俊杰 on 2020/4/24.
- //
- #ifndef PolynomialCurve_h
- #define PolynomialCurve_h
- #include "rparticle/Macros/RParticleMacros.h"
- NS_RRP_BEGIN
- template<class T>
- class AnimationCurveTpl;
- typedef AnimationCurveTpl<float> AnimationCurve;
- //class Vector2f;
- struct Polynomial
- {
- static float EvalSegment (float t, const float* coeff)
- {
- return (t * (t * (t * coeff[0] + coeff[1]) + coeff[2])) + coeff[3];
- }
-
- float coeff[4];
- };
- // Smaller, optimized version
- struct OptimizedPolynomialCurve
- {
- enum { kMaxPolynomialKeyframeCount = 3, kSegmentCount = kMaxPolynomialKeyframeCount-1, };
-
- Polynomial segments[kSegmentCount];
-
- float timeValue;
- float velocityValue;
-
- // Evaluate double integrated Polynomial curve.
- // Example: position = EvaluateDoubleIntegrated (normalizedTime) * startEnergy^2
- // Use DoubleIntegrate function to for example turn a force curve into a position curve.
- // Expects that t is in the 0...1 range.
- float EvaluateDoubleIntegrated (float t) const
- {
- DebugAssert(t >= -0.01F && t <= 1.01F);
- float res0, res1;
-
- // All segments are added together. At t = 0, the integrated curve is always zero.
-
- // 0 segment is sampled up to the 1 keyframe
- // First key is always assumed to be at 0 time
- float t1 = std::min(t, timeValue);
-
- // 1 segment is sampled from 1 key to 2 key
- // Last key is always assumed to be at 1 time
- float t2 = std::max(0.0F, t - timeValue);
-
- res0 = Polynomial::EvalSegment(t1, segments[0].coeff) * t1 * t1;
- res1 = Polynomial::EvalSegment(t2, segments[1].coeff) * t2 * t2;
-
- float finalResult = res0 + res1;
-
- // Add velocity of previous segments
- finalResult += velocityValue * std::max(t - timeValue, 0.0F);
-
- return finalResult;
- }
-
- // Evaluate integrated Polynomial curve.
- // Example: position = EvaluateIntegrated (normalizedTime) * startEnergy
- // Use Integrate function to for example turn a velocity curve into a position curve.
- // Expects that t is in the 0...1 range.
- float EvaluateIntegrated (float t) const
- {
- DebugAssert(t >= -0.01F && t <= 1.01F);
- float res0, res1;
-
- // All segments are added together. At t = 0, the integrated curve is always zero.
-
- // 0 segment is sampled up to the 1 keyframe
- // First key is always assumed to be at 0 time
- float t1 = std::min(t, timeValue);
-
- // 1 segment is sampled from 1 key to 2 key
- // Last key is always assumed to be at 1 time
- float t2 = std::max(0.0F, t - timeValue);
-
- res0 = Polynomial::EvalSegment(t1, segments[0].coeff) * t1;
- res1 = Polynomial::EvalSegment(t2, segments[1].coeff) * t2;
-
- return (res0 + res1);
- }
-
- // Evaluate the curve
- // extects that t is in the 0...1 range
- float Evaluate (float t) const
- {
- DebugAssert(t >= -0.01F && t <= 1.01F);
-
- float res0 = Polynomial::EvalSegment(t, segments[0].coeff);
- float res1 = Polynomial::EvalSegment(t - timeValue, segments[1].coeff);
-
- float result;
- if (t > timeValue)
- result = res1;
- else
- result = res0;
-
- return result;
- }
-
- // Find the maximum of a double integrated curve (x: min, y: max)
- Vector2f FindMinMaxDoubleIntegrated() const;
-
- // Find the maximum of the integrated curve (x: min, y: max)
- Vector2f FindMinMaxIntegrated() const;
-
- // Precalculates polynomials from the animation curve and a scale factor
- bool BuildOptimizedCurve (const AnimationCurve& editorCurve, float scale);
-
- // Integrates a velocity curve to be a position curve.
- // You have to call EvaluateIntegrated to evaluate the curve
- void Integrate ();
-
- // Integrates a velocity curve to be a position curve.
- // You have to call EvaluateDoubleIntegrated to evaluate the curve
- void DoubleIntegrate ();
-
- // Add a constant force to a velocity curve
- // Assumes that you have already called Integrate on the velocity curve.
- void AddConstantForceToVelocityCurve (float gravity)
- {
- for (int i=0;i<kSegmentCount;i++)
- segments[i].coeff[1] += 0.5F * gravity;
- }
- };
- // Bigger, not so optimized version
- struct PolynomialCurve
- {
- enum{ kMaxNumSegments = 8 };
-
- Polynomial segments[kMaxNumSegments]; // Cached polynomial coefficients
- float integrationCache[kMaxNumSegments]; // Cache of integrated values up until start of segments
- float doubleIntegrationCache[kMaxNumSegments]; // Cache of double integrated values up until start of segments
- float times[kMaxNumSegments]; // Time value for end of segment
-
- int segmentCount;
-
- // Find the maximum of a double integrated curve (x: min, y: max)
- Vector2f FindMinMaxDoubleIntegrated() const;
-
- // Find the maximum of the integrated curve (x: min, y: max)
- Vector2f FindMinMaxIntegrated() const;
-
- // Precalculates polynomials from the animation curve and a scale factor
- bool BuildCurve(const AnimationCurve& editorCurve, float scale);
-
- // Integrates a velocity curve to be a position curve.
- // You have to call EvaluateIntegrated to evaluate the curve
- void Integrate ();
-
- // Integrates a velocity curve to be a position curve.
- // You have to call EvaluateDoubleIntegrated to evaluate the curve
- void DoubleIntegrate ();
-
- // Evaluates if it is possible to represent animation curve as PolynomialCurve
- static bool IsValidCurve(const AnimationCurve& editorCurve);
-
- // Evaluate double integrated Polynomial curve.
- // Example: position = EvaluateDoubleIntegrated (normalizedTime) * startEnergy^2
- // Use DoubleIntegrate function to for example turn a force curve into a position curve.
- // Expects that t is in the 0...1 range.
- float EvaluateDoubleIntegrated (float t) const
- {
- DebugAssert(t >= -0.01F && t <= 1.01F);
-
- float prevTimeValue = 0.0f;
- for(int i = 0; i < segmentCount; i++)
- {
- if(t <= times[i])
- {
- const float time = t - prevTimeValue;
- return doubleIntegrationCache[i] + integrationCache[i] * time + Polynomial::EvalSegment(time, segments[i].coeff) * time * time;
- }
- prevTimeValue = times[i];
- }
- DebugAssert(!"PolyCurve: Outside segment range!");
- return 1.0f;
- }
-
- // Evaluate integrated Polynomial curve.
- // Example: position = EvaluateIntegrated (normalizedTime) * startEnergy
- // Use Integrate function to for example turn a velocity curve into a position curve.
- // Expects that t is in the 0...1 range.
- float EvaluateIntegrated (float t) const
- {
- DebugAssert(t >= -0.01F && t <= 1.01F);
-
- float prevTimeValue = 0.0f;
- for(int i = 0; i < segmentCount; i++)
- {
- if(t <= times[i])
- {
- const float time = t - prevTimeValue;
- return integrationCache[i] + Polynomial::EvalSegment(time, segments[i].coeff) * time;
- }
- prevTimeValue = times[i];
- }
- DebugAssert(!"PolyCurve: Outside segment range!");
- return 1.0f;
- }
-
- // Evaluate the curve
- // extects that t is in the 0...1 range
- float Evaluate(float t) const
- {
- DebugAssert(t >= -0.01F && t <= 1.01F);
-
- float prevTimeValue = 0.0f;
- for(int i = 0; i < segmentCount; i++)
- {
- if(t <= times[i])
- return Polynomial::EvalSegment(t - prevTimeValue, segments[i].coeff);
- prevTimeValue = times[i];
- }
- DebugAssert(!"PolyCurve: Outside segment range!");
- return 1.0f;
- }
- };
- void SetPolynomialCurveToValue (AnimationCurve& a, OptimizedPolynomialCurve& c, float value);
- void SetPolynomialCurveToLinear (AnimationCurve& a, OptimizedPolynomialCurve& c);
- void ConstrainToPolynomialCurve (AnimationCurve& curve);
- bool IsValidPolynomialCurve (const AnimationCurve& curve);
- void CalculateMinMax(Vector2f& minmax, float value);
- NS_RRP_END
- #endif /* PolynomialCurve_h */
|