1 // Copyright (C) 2012-2019 The VPaint Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution
3 // and at https://github.com/dalboris/vpaint/blob/master/COPYRIGHT
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #include "KeyFrame.h"
18 #include "Timeline.h"
19 
20 // ----------- KeyFrame Line -----------------
21 
AnimatedData()22 AnimatedData::AnimatedData() :
23     first(0), last(0), current(0)
24 {
25     // TODO: find some  way to have the correct  frame when creating
26     // the animated data. Here, we assume it is created at frame 0
27 
28     // now, it's possible thanks to the static currentFrame() method
29     // be  careful,  it  means  there  can't  be  2  timelines  with
30     // different currentFrame in the software
31 
32     currentFrame = 0;//Timeline::currentFrame();
33 }
34 
35 
updateCurrent(int frame)36 void AnimatedData::updateCurrent(int frame)
37 {
38     // ideally this operation should be the faster for, in order:
39     //   - frame = currentFrame+1
40     //   - frame = currentFrame-1
41     //   - frame ~ currentFrame
42     //   - frame = playingWindowFirstFrame
43     //   - frame = playingWindowLastFrame
44     //   - arbitrary position
45     //
46     // It would  be nice  to modify it  for arbitrary  position, for
47     // instance using a table to  access in constant time a keyframe
48     // located at a specific "N second" window. (for large animation)
49     //
50     // A simpler idea  is also to find the  closest keyframe between
51     // first, current and last,  and search from that starting point
52     // (instead of always using current except when out of bound)
53 
54     if(currentFrame == frame)
55         return;
56 
57     currentFrame = frame;
58 
59     // at most one keyframe
60     if(first == last)
61         return;
62 
63     // at least two keyframes
64     if(frame <= first->frame)
65         current = first;
66     else if(frame >= last->frame)
67         current = last;
68     else
69     {
70         while(current->frame < frame)
71             current = current->next;
72         while(current->frame > frame)
73             current = current->previous;
74     }
75 }
76 
insertKeyFrame(KeyFrame * k)77 void AnimatedData::insertKeyFrame(KeyFrame *k)
78 {
79     // configuration 1: there exists no keyframe yet
80     if(first == 0)
81     {
82         k->previous = 0;
83         k->next = 0;
84 
85         first = k;
86         last = k;
87         current = k;
88     }
89 
90     // configuration 2: there exists one and only one keyframe
91     else if(first == last)
92     {
93         // the new keyframe should replace the existed one
94         if(k->frame == first->frame)
95         {
96             delete first;
97 
98             // back to configuration 1
99             k->previous = 0;
100             k->next = 0;
101 
102             first = k;
103             last = k;
104             current = k;
105         }
106         else // there exists now exactly two keyframes
107         {
108             if(k->frame < first->frame)
109             {
110                 k->previous = 0;
111                 k->next = first;
112                 k->next->previous = k;
113                 first = k;
114             }
115             else //(k->frame > first->frame)
116             {
117                 k->previous = first;
118                 k->next = 0;
119                 k->previous->next = k;
120                 last = k;
121             }
122 
123             if(currentFrame < last->frame)
124                 current = first;
125             else
126                 current = last;
127         }
128     }
129 
130     // configuration 3: there exists already at least 2 keyframes
131     else
132     {
133         // first, deals with extreme cases
134         if(k->frame < first->frame)
135         {
136             k->previous = 0;
137             k->next = first;
138             k->next->previous = k;
139 
140             if(currentFrame < first->frame)
141                 current = k;
142 
143             first = k;
144         }
145         else if(k->frame == first->frame)
146         {
147             k->previous = 0;
148             k->next = first->next;
149             k->next->previous = k;
150 
151             if(current == first)
152                 current = k;
153 
154             delete first;
155             first = k;
156         }
157         else if(k->frame == last->frame)
158         {
159             k->previous = last->previous;
160             k->next = 0;
161             k->previous->next = k;
162 
163             if(current == last)
164                 current = k;
165 
166             delete last;
167             last = k;
168         }
169         else if(k->frame > last->frame)
170         {
171             k->previous = last;
172             k->next = 0;
173             k->previous->next = k;
174 
175             if(currentFrame >= k->frame)
176                 current = k;
177 
178             last = k;
179         }
180 
181 
182         else // first < k < last
183         {
184             // only one should be fine
185             KeyFrame *beforeOrEqualK;
186             if(currentFrame <= first->frame)
187                 beforeOrEqualK = first;
188             else if(currentFrame >= last->frame)
189                 beforeOrEqualK = last;
190             else
191                 beforeOrEqualK = current;
192 
193             while(beforeOrEqualK->frame < k->frame)
194                 beforeOrEqualK = beforeOrEqualK->next;
195             while(beforeOrEqualK->frame > k->frame)
196                 beforeOrEqualK = beforeOrEqualK->previous;
197 
198             // Equal: replace the keyframe
199             if(beforeOrEqualK->frame == k->frame)
200             {
201                 k->previous = beforeOrEqualK->previous;
202                 k->next = beforeOrEqualK->next;
203                 k->next->previous = k;
204                 k->previous->next = k;
205 
206                 if(current == beforeOrEqualK)
207                     current = k;
208 
209                 delete beforeOrEqualK;
210             }
211             else // Before: insert the keyframe
212             {
213                 k->previous = beforeOrEqualK;
214                 k->next = beforeOrEqualK->next;
215                 k->next->previous = k;
216                 k->previous->next = k;
217 
218                 if(current == beforeOrEqualK && currentFrame >= k->frame)
219                     current = k;
220             }
221         }
222     }
223 }
224 
createKeyFrame(int frame,double d)225 void AnimatedDouble::createKeyFrame(int frame, double d)
226 {
227     KeyFrameDouble *k = new KeyFrameDouble(frame, d);
228     insertKeyFrame(k);
229 }
230 
value(int frame)231 double AnimatedDouble::value(int frame)
232 {
233     // TODO: avoid doing this everytime (well, maybe not...)
234     currentFrame = frame;
235     updateCurrent(frame);
236 
237     // configuration 1: no keyframe -> return default value
238     if(!first)
239         return 0;
240 
241     // configuration 2: one keyframe -> return this value
242     else if(first == last)
243         return static_cast<KeyFrameDouble*>(first)->value;
244 
245     // configuration 3-1: before first frame -> return first
246     else if(currentFrame <= first->frame)
247         return static_cast<KeyFrameDouble*>(first)->value;
248 
249     // configuration 3-2: after last frame -> return last
250     else if(currentFrame >= last->frame)
251         return static_cast<KeyFrameDouble*>(last)->value;
252 
253     // configuration 3-3: at a specific keyframe -> return it
254     else if(currentFrame == current->frame)
255         return static_cast<KeyFrameDouble*>(current)->value;
256 
257     // configuration 3-4: strictly between two frame -> interpolate
258     else
259     {
260         // by now, linear interpolation
261         int t1 = current->frame;
262         double d1 = static_cast<KeyFrameDouble*>(current)->value;
263 
264         int t2 = current->next->frame;
265         double d2 = static_cast<KeyFrameDouble*>(current->next)->value;
266 
267         double u = (double)(currentFrame - t1) / (double)(t2 - t1);
268 
269         return d1 + u*(d2-d1);
270     }
271 }
272