1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_layers_AxisPhysicsModel_h
8 #define mozilla_layers_AxisPhysicsModel_h
9 
10 #include <sys/types.h>          // for int32_t
11 #include "mozilla/TimeStamp.h"  // for TimeDuration
12 
13 namespace mozilla {
14 namespace layers {
15 
16 /**
17  * AxisPhysicsModel encapsulates a generic 1-dimensional physically-based motion
18  * model.
19  *
20  * It performs frame-rate independent interpolation and RK4 integration for
21  * smooth animation with stable, deterministic behavior.
22  * Implementations are expected to subclass and override the Acceleration()
23  * method.
24  */
25 class AxisPhysicsModel {
26  public:
27   AxisPhysicsModel(double aInitialPosition, double aInitialVelocity);
28   virtual ~AxisPhysicsModel();
29 
30   /**
31    * Advance the physics simulation.
32    * |aDelta| is the time since the last sample.
33    */
34   void Simulate(const TimeDuration& aDeltaTime);
35 
36   /**
37    * Gets the raw velocity of this axis at this moment.
38    */
39   double GetVelocity() const;
40 
41   /**
42    * Sets the raw velocity of this axis at this moment.
43    */
44   void SetVelocity(double aVelocity);
45 
46   /**
47    * Gets the raw position of this axis at this moment.
48    */
49   double GetPosition() const;
50 
51   /**
52    * Sets the raw position of this axis at this moment.
53    */
54   void SetPosition(double aPosition);
55 
56  protected:
57   struct State {
StateState58     State(double ap, double av) : p(ap), v(av){};
59     double p;  // Position
60     double v;  // Velocity
61   };
62 
63   struct Derivative {
DerivativeDerivative64     Derivative() : dp(0.0), dv(0.0){};
DerivativeDerivative65     Derivative(double aDp, double aDv) : dp(aDp), dv(aDv){};
66     double dp;  // dp / delta time = Position
67     double dv;  // dv / delta time = Velocity
68   };
69 
70   /**
71    * Acceleration must be overridden and return the number of
72    * axis-position-units / second that should be added or removed from the
73    * velocity.
74    */
75   virtual double Acceleration(const State& aState) = 0;
76 
77  private:
78   /**
79    * Duration of fixed delta time step (seconds)
80    */
81   static const double kFixedTimestep;
82 
83   /**
84    * 0.0 - 1.0 value indicating progress between current and next simulation
85    * sample.  Normalized to units of kFixedTimestep duration.
86    */
87   double mProgress;
88 
89   /**
90    * Sample of simulation state as it existed
91    * (1.0 - mProgress) * kFixedTimestep seconds in the past.
92    */
93   State mPrevState;
94 
95   /**
96    * Sample of simulation state as it will be in mProgress * kFixedTimestep
97    * seconds in the future.
98    */
99   State mNextState;
100 
101   /**
102    * Perform RK4 (Runge-Kutta method) Integration to calculate the next
103    * simulation sample.
104    */
105   void Integrate(double aDeltaTime);
106 
107   /**
108    * Apply delta velocity and position represented by aDerivative over
109    * aDeltaTime seconds, calculate new acceleration, and return new deltas.
110    */
111   Derivative Evaluate(const State& aInitState, double aDeltaTime,
112                       const Derivative& aDerivative);
113 
114   /**
115    * Helper function for performing linear interpolation (lerp) of double's
116    */
117   static double LinearInterpolate(double aV1, double aV2, double aBlend);
118 };
119 
120 }  // namespace layers
121 }  // namespace mozilla
122 
123 #endif
124