friz
An animation control system for JUCE
Loading...
Searching...
No Matches
animation.h
1/*
2 Copyright (c) 2019-2023 Brett g Porter
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21*/
22#pragma once
23
24// #include "../animatorApp.h"
25#include <array>
26
27#include "../curves/animatedValue.h"
28
29namespace friz
30{
31
39{
40public:
41 enum class Status
42 {
45 };
46
47 AnimationType (int id)
48 : animationId { id }
49 , preDelay { 0 }
50 {
51 // only allow positive animation IDs.
52 jassert (id >= 0);
53 }
54
55 virtual ~AnimationType () = default;
56
60 int getId () const { return animationId; }
61
66 void setDelay (int delay) { preDelay = std::max (0, delay); }
67
68 virtual bool setValue (size_t /*index*/, std::unique_ptr<AnimatedValue> /*value*/)
69 {
70 jassertfalse;
71 return false;
72 }
73
81 virtual Status gotoTime (juce::int64 timeInMs) = 0;
82
89 virtual void cancel (bool moveToEndPosition) = 0;
90
94 virtual bool isFinished () = 0;
95
100 virtual bool isReady () const = 0;
101
108 virtual AnimatedValue* getValue (size_t index) = 0;
115 using CompletionFn = std::function<void (int, bool)>;
122 void onCompletion (CompletionFn complete) { completionFn = complete; }
123
124public:
127
128protected:
130 int animationId { 0 };
131
133 int preDelay { 0 };
134};
135
136template <std::size_t ValueCount> class UpdateSource
137{
138public:
139 UpdateSource () = default;
140 using ValueList = std::array<float, ValueCount>;
141 using UpdateFn = std::function<void (int, const ValueList&)>;
147 void onUpdate (UpdateFn update) { updateFn = update; }
148
151 UpdateFn updateFn;
152};
153
165template <std::size_t ValueCount>
167 public UpdateSource<ValueCount>
168{
169public:
170 using SourceList = std::array<std::unique_ptr<AnimatedValue>, ValueCount>;
171 using ValueList = typename UpdateSource<ValueCount>::ValueList;
172
181 Animation (int id = 0)
182 : AnimationType { id }
183 {
184 }
185
192 Animation (SourceList&& sources, int id = 0)
193 : AnimationType { id }
194 , sources { std::move (sources) }
195 {
196 }
197
204 bool setValue (size_t index, std::unique_ptr<AnimatedValue> value) override
205 {
206 if (index >= ValueCount)
207 {
208 jassertfalse;
209 return false;
210 }
211
212 sources[index] = std::move (value);
213 return true;
214 }
215
223 AnimatedValue* getValue (size_t index) override
224 {
225 if (index < ValueCount)
226 return sources[index].get ();
227
228 jassertfalse;
229 return nullptr;
230 }
231
239 Status gotoTime (juce::int64 timeInMs) override
240 {
241 if (finished)
242 {
243 if (completionFn != nullptr)
244 completionFn (getId (), false);
245 return Status::finished;
246 }
247
248 juce::int64 deltaTime;
249 // if this is the first time we're being executed, perform some setup:
250 if (startTime < 0)
251 {
252 startTime = lastTime = timeInMs;
253 deltaTime = 0;
254 }
255 else
256 {
257 deltaTime = timeInMs - lastTime;
258 lastTime = timeInMs;
259 }
260
261 const auto totalElapsed { timeInMs - startTime };
262
263 // if we're still delaying, just return.
264 if (totalElapsed < preDelay)
265 return Status::processing;
266
267 // recalculate the elapsed and delta times to account for an
268 // expired delay
269 const auto effectElapsed { totalElapsed - preDelay };
270 deltaTime = std::min (deltaTime, totalElapsed);
271
272 // loop through our value generators and update:
273 ValueList values;
274 int completeCount { 0 };
275
276 for (int i = 0; i < ValueCount; ++i)
277 {
278 auto& val = sources[i];
279 if (val != nullptr)
280 {
281 // values[i] = val->GetNextValue ();
282 values[i] = val->getNextValue (static_cast<int> (effectElapsed),
283 static_cast<int> (deltaTime));
284 completeCount += (val->isFinished ()) ? 1 : 0;
285 }
286 else
287 jassertfalse;
288 }
289
290 if (this->updateFn != nullptr)
291 this->updateFn (getId (), values);
292
293 if (completeCount == ValueCount)
294 finished = true;
295
296 return Status::processing;
297 }
298
299 void cancel (bool moveToEndPosition) override
300 {
301 for (auto& val : sources)
302 {
303 if (val != nullptr)
304 val->cancel (moveToEndPosition);
305 }
306
307 if (moveToEndPosition && this->updateFn != nullptr)
308 {
309 // send one more update where all of the individual values
310 // have snapped to their end states.
311 ValueList values;
312 for (int i = 0; i < ValueCount; ++i)
313 {
314 auto& val = sources[i];
315 jassert (val != nullptr);
316 if (val != nullptr)
317 values[i] = val->getEndValue ();
318 }
319 this->updateFn (getId (), values);
320 }
321
322 // notify that the effect is complete.
323 if (completionFn != nullptr)
324 completionFn (getId (), true);
325 finished = true;
326 }
327
328 bool isFinished () override { return finished; }
329
330 bool isReady () const override
331 {
332 for (auto& src : sources)
333 {
334 if (nullptr == src.get ())
335 return false;
336 }
337 return true;
338 }
339
340public:
341private:
343 juce::int64 startTime { -1 };
345 juce::int64 lastTime { -1 };
346
348 bool finished { false };
349
351 SourceList sources;
352};
353
368template <class T, int ValueCount, class... Args>
369std::unique_ptr<Animation<ValueCount>> makeAnimation (
370 int id, std::array<float, ValueCount>&& from, std::array<float, ValueCount>&& to,
371 Args... args)
372{
373 // make sure we're trying to create an animation object.
374 static_assert (std::is_base_of<AnimatedValue, T>::value);
375
376 auto animation { std::make_unique<Animation<ValueCount>> (id) };
377
378 for (int i { 0 }; i < ValueCount; ++i)
379 {
380 auto curve { std::make_unique<T> (from[i], to[i], std::forward<Args> (args)...) };
381 animation->setValue (i, std::move (curve));
382 }
383
384 return animation;
385}
386
391template <class T, class... Args>
392std::unique_ptr<Animation<1>> makeAnimation (int id, float from, float to, Args... args)
393{
394 return makeAnimation<T, 1> (id, { from }, { to }, std::forward<Args> (args)...);
395}
396
397} // namespace friz
Abstract base class for objects that can generate a useful series of values to drive UI animations.
Definition: animatedValue.h:34
This class owns a number of AnimatedValue objects. On each animation frame it gets the next calculate...
Definition: animation.h:168
Animation(int id=0)
Definition: animation.h:181
bool isFinished() override
Definition: animation.h:328
bool finished
is this animation complete?
Definition: animation.h:348
Status gotoTime(juce::int64 timeInMs) override
Advance to the specified time, sending value updates to the code that's waiting for them.
Definition: animation.h:239
juce::int64 startTime
Timestamp of first update.
Definition: animation.h:343
bool setValue(size_t index, std::unique_ptr< AnimatedValue > value) override
Definition: animation.h:204
SourceList sources
The array of animated value objects.
Definition: animation.h:351
Animation(SourceList &&sources, int id=0)
Construct a new Animation object, given a list of value sources.
Definition: animation.h:192
void cancel(bool moveToEndPosition) override
Cancel an in-progress animation, optionally moving directly to its end value.
Definition: animation.h:299
juce::int64 lastTime
timestamp of most recent update.
Definition: animation.h:345
AnimatedValue * getValue(size_t index) override
Retrieve a pointer to one of this animation's value sources. This should probably not be used very mu...
Definition: animation.h:223
bool isReady() const override
Definition: animation.h:330
Abstract base class; all the real action happens in the derived templated Animation class,...
Definition: animation.h:39
Status
Definition: animation.h:42
@ processing
The animation is running right now.
@ finished
Finished running, okay to clean up.
virtual bool isFinished()=0
virtual AnimatedValue * getValue(size_t index)=0
Retrieve a pointer to one of this animation's value objects.
virtual bool isReady() const =0
int animationId
optional ID value for this animation.
Definition: animation.h:130
virtual Status gotoTime(juce::int64 timeInMs)=0
Advance all active animations to this point in time.
int preDelay
an optional pre-delay before beginning to execute the effect.
Definition: animation.h:133
int getId() const
Definition: animation.h:60
CompletionFn completionFn
function to call when the animation is completed or canceled.
Definition: animation.h:126
void onCompletion(CompletionFn complete)
Definition: animation.h:122
virtual void cancel(bool moveToEndPosition)=0
Cancel an in-progress animation, optionally moving directly to its end value.
void setDelay(int delay)
Definition: animation.h:66
std::function< void(int, bool)> CompletionFn
callback on completion of this effect
Definition: animation.h:115
Definition: animation.h:137
void onUpdate(UpdateFn update)
Definition: animation.h:147
UpdateFn updateFn
Definition: animation.h:151