up-to-date submodule (rive-cpp)
[platform/core/uifw/rive-tizen.git] / submodule / src / animation / linear_animation_instance.cpp
1 #include "animation/linear_animation_instance.hpp"
2 #include "animation/linear_animation.hpp"
3 #include "animation/loop.hpp"
4 #include <cmath>
5
6 using namespace rive;
7
8 LinearAnimationInstance::LinearAnimationInstance(
9     const LinearAnimation* animation) :
10     m_Animation(animation),
11     m_Time(animation->enableWorkArea()
12                ? (float)animation->workStart() / animation->fps()
13                : 0),
14     m_TotalTime(0.0f),
15     m_LastTotalTime(0.0f),
16     m_SpilledTime(0.0f),
17     m_Direction(1)
18 {
19 }
20
21 bool LinearAnimationInstance::advance(float elapsedSeconds)
22 {
23         const LinearAnimation& animation = *m_Animation;
24         m_Time += elapsedSeconds * animation.speed() * m_Direction;
25         m_LastTotalTime = m_TotalTime;
26         m_TotalTime += elapsedSeconds;
27
28         int fps = animation.fps();
29
30         float frames = m_Time * fps;
31
32         int start = animation.enableWorkArea() ? animation.workStart() : 0;
33         int end =
34             animation.enableWorkArea() ? animation.workEnd() : animation.duration();
35         int range = end - start;
36
37         bool keepGoing = true;
38         bool didLoop = false;
39         m_SpilledTime = 0.0f;
40
41         switch (animation.loop())
42         {
43                 case Loop::oneShot:
44                         if (m_Direction == 1 && frames > end)
45                         {
46                                 keepGoing = false;
47                                 m_SpilledTime = (frames - end) / fps;
48                                 frames = end;
49                                 m_Time = frames / fps;
50                                 didLoop = true;
51                         }
52                         else if (m_Direction == -1 && frames < start)
53                         {
54                                 keepGoing = false;
55                                 m_SpilledTime = (start - frames) / fps;
56                                 frames = start;
57                                 m_Time = frames / fps;
58                                 didLoop = true;
59                         }
60                         break;
61                 case Loop::loop:
62                         if (m_Direction == 1 && frames >= end)
63                         {
64                                 m_SpilledTime = (frames - end) / fps;
65                                 frames = m_Time * fps;
66                                 frames = start + std::fmod(frames - start, range);
67
68                                 m_Time = frames / fps;
69                                 didLoop = true;
70                         }
71                         else if (m_Direction == -1 && frames <= start)
72                         {
73
74                                 m_SpilledTime = (start - frames) / fps;
75                                 frames = m_Time * fps;
76                                 frames = end - std::abs(std::fmod(start - frames, range));
77                                 m_Time = frames / fps;
78                                 didLoop = true;
79                         }
80                         break;
81                 case Loop::pingPong:
82                         while (true)
83                         {
84                                 if (m_Direction == 1 && frames >= end)
85                                 {
86                                         m_SpilledTime = (frames - end) / fps;
87                                         m_Direction = -1;
88                                         frames = end + (end - frames);
89                                         m_Time = frames / fps;
90                                         didLoop = true;
91                                 }
92                                 else if (m_Direction == -1 && frames < start)
93                                 {
94                                         m_SpilledTime = (start - frames) / fps;
95                                         m_Direction = 1;
96                                         frames = start + (start - frames);
97                                         m_Time = frames / fps;
98                                         didLoop = true;
99                                 }
100                                 else
101                                 {
102                                         // we're within the range, we can stop fixing. We do this in
103                                         // a loop to fix conditions when time has advanced so far
104                                         // that we've ping-ponged back and forth a few times in a
105                                         // single frame. We want to accomodate for this in cases
106                                         // where animations are not advanced on regular intervals.
107                                         break;
108                                 }
109                         }
110                         break;
111         }
112
113         m_DidLoop = didLoop;
114         return keepGoing;
115 }
116
117 void LinearAnimationInstance::time(float value)
118 {
119         if (m_Time == value)
120         {
121                 return;
122         }
123         m_Time = value;
124         // Make sure to keep last and total in relative lockstep so state machines
125         // can track change even when setting time.
126         auto diff = m_TotalTime - m_LastTotalTime;
127
128         int start = (m_Animation->enableWorkArea() ? m_Animation->workStart() : 0) *
129                     m_Animation->fps();
130         m_TotalTime = value - start;
131         m_LastTotalTime = m_TotalTime - diff;
132
133         // leaving this RIGHT now. but is this required? it kinda messes up
134         // playing things backwards and seeking. what purpose does it solve?
135         m_Direction = 1;
136 }