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