1 /*
2  This file is part of the Tweeny library.
3 
4  Copyright (c) 2016-2018 Leonardo G. Lucena de Freitas
5  Copyright (c) 2016 Guilherme R. Costa
6 
7  Permission is hereby granted, free of charge, to any person obtaining a copy of
8  this software and associated documentation files (the "Software"), to deal in
9  the Software without restriction, including without limitation the rights to
10  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  the Software, and to permit persons to whom the Software is furnished to do so,
12  subject to the following conditions:
13 
14  The above copyright notice and this permission notice shall be included in all
15  copies or substantial portions of the Software.
16 
17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 
25 /*
26  * The purpose of this file is to hold implementations for the tween.h file, s
27  * pecializing on the single value case.
28  */
29 #ifndef TWEENY_TWEENONE_TCC
30 #define TWEENY_TWEENONE_TCC
31 
32 #include "tween.h"
33 #include "dispatcher.h"
34 
35 namespace tweeny {
from(T t)36     template<typename T> inline tween<T> tween<T>::from(T t) { return tween<T>(t); }
tween()37     template<typename T> inline tween<T>::tween() { }
tween(T t)38     template<typename T> inline tween<T>::tween(T t) {
39         points.emplace_back(t);
40     }
41 
to(T t)42     template<typename T> inline tween<T> & tween<T>::to(T t) {
43         points.emplace_back(t);
44         return *this;
45     }
46 
47     template<typename T>
48     template<typename... Fs>
via(Fs...vs)49     inline tween<T> & tween<T>::via(Fs... vs) {
50         points.at(points.size() - 2).via(vs...);
51         return *this;
52     }
53 
54     template<typename T>
55     template<typename... Fs>
via(int index,Fs...vs)56     inline tween<T> & tween<T>::via(int index, Fs... vs) {
57         points.at(static_cast<size_t>(index)).via(vs...);
58         return *this;
59     }
60 
61     template<typename T>
62     template<typename... Ds>
during(Ds...ds)63     inline tween<T> & tween<T>::during(Ds... ds) {
64         total = 0;
65         points.at(points.size() - 2).during(ds...);
66         for (detail::tweenpoint<T> & p : points) {
67             total += p.duration();
68             p.stacked = total;
69         }
70         return *this;
71     }
72 
73     template<typename T>
step(int32_t dt,bool suppress)74     inline const T & tween<T>::step(int32_t dt, bool suppress) {
75         return step(static_cast<float>(dt * currentDirection)/static_cast<float>(total), suppress);
76     }
77 
78     template<typename T>
step(uint32_t dt,bool suppress)79     inline const T & tween<T>::step(uint32_t dt, bool suppress) {
80         return step(static_cast<int32_t>(dt), suppress);
81     }
82 
83     template<typename T>
step(float dp,bool suppress)84     inline const T & tween<T>::step(float dp, bool suppress) {
85         seek(currentProgress + dp, true);
86         if (!suppress) dispatch(onStepCallbacks);
87         return current;
88     }
89 
90     template<typename T>
seek(float p,bool suppress)91     inline const T & tween<T>::seek(float p, bool suppress) {
92         p = detail::clip(p, 0.0f, 1.0f);
93         currentProgress = p;
94         render(p);
95         if (!suppress) dispatch(onSeekCallbacks);
96         return current;
97     }
98 
99     template<typename T>
seek(int32_t t,bool suppress)100     inline const T & tween<T>::seek(int32_t t, bool suppress) {
101         return seek(static_cast<float>(t) / static_cast<float>(total), suppress);
102     }
103 
104     template<typename T>
seek(uint32_t t,bool suppress)105     inline const T & tween<T>::seek(uint32_t t, bool suppress) {
106         return seek(static_cast<float>(t) / static_cast<float>(total), suppress);
107     }
108 
109     template<typename T>
duration() const110     inline uint32_t tween<T>::duration() const {
111         return total;
112     }
113 
114     template<typename T>
interpolate(float prog,unsigned point,T & value) const115     inline void tween<T>::interpolate(float prog, unsigned point, T & value) const {
116         auto & p = points.at(point);
117         uint32_t pointDuration = p.duration() - (p.stacked - (prog * static_cast<float>(total)));
118         float pointTotal = static_cast<float>(pointDuration) / static_cast<float>(p.duration());
119         if (pointTotal > 1.0f) pointTotal = 1.0f;
120         auto easing = std::get<0>(p.easings);
121         value = easing(pointTotal, std::get<0>(p.values), std::get<0>(points.at(point+1).values));
122     }
123 
124     template<typename T>
render(float p)125     inline void tween<T>::render(float p) {
126         currentPoint = pointAt(p);
127         interpolate(p, currentPoint, current);
128     }
129 
130     template<typename T>
onStep(typename detail::tweentraits<T>::callbackType callback)131     tween<T> & tween<T>::onStep(typename detail::tweentraits<T>::callbackType callback) {
132         onStepCallbacks.push_back(callback);
133         return *this;
134     }
135 
136     template<typename T>
onStep(typename detail::tweentraits<T>::noValuesCallbackType callback)137     tween<T> & tween<T>::onStep(typename detail::tweentraits<T>::noValuesCallbackType callback) {
138         onStepCallbacks.push_back([callback](tween<T> & tween, T) { return callback(tween); });
139         return *this;
140     }
141 
142     template<typename T>
onStep(typename detail::tweentraits<T>::noTweenCallbackType callback)143     tween<T> & tween<T>::onStep(typename detail::tweentraits<T>::noTweenCallbackType callback) {
144         onStepCallbacks.push_back([callback](tween<T> &, T v) { return callback(v); });
145         return *this;
146     }
147 
148     template<typename T>
onSeek(typename detail::tweentraits<T>::callbackType callback)149     tween<T> & tween<T>::onSeek(typename detail::tweentraits<T>::callbackType callback) {
150         onSeekCallbacks.push_back(callback);
151         return *this;
152     }
153 
154     template<typename T>
onSeek(typename detail::tweentraits<T>::noValuesCallbackType callback)155     tween<T> & tween<T>::onSeek(typename detail::tweentraits<T>::noValuesCallbackType callback) {
156         onSeekCallbacks.push_back([callback](tween<T> & t, T) { return callback(t); });
157         return *this;
158     }
159 
160     template<typename T>
onSeek(typename detail::tweentraits<T>::noTweenCallbackType callback)161     tween<T> & tween<T>::onSeek(typename detail::tweentraits<T>::noTweenCallbackType callback) {
162         onSeekCallbacks.push_back([callback](tween<T> &, T v) { return callback(v); });
163         return *this;
164     }
165 
166     template<typename T>
dispatch(std::vector<typename traits::callbackType> & cbVector)167     void tween<T>::dispatch(std::vector<typename traits::callbackType> & cbVector) {
168         std::vector<size_t> dismissed;
169         for (size_t i = 0; i < cbVector.size(); ++i) {
170             auto && cb = cbVector[i];
171             bool dismiss = cb(*this, current);
172             if (dismiss) dismissed.push_back(i);
173         }
174 
175         if (dismissed.size() > 0) {
176             for (size_t i = 0; i < dismissed.size(); ++i) {
177                 size_t index = dismissed[i];
178                 cbVector[index] = cbVector.at(cbVector.size() - 1 - i);
179             }
180             cbVector.resize(cbVector.size() - dismissed.size());
181         }
182     }
183 
184     template<typename T>
peek() const185     const T & tween<T>::peek() const {
186         return current;
187     }
188 
189 
190     template<typename T>
peek(float progress) const191     T tween<T>::peek(float progress) const {
192         T value;
193         interpolate(progress, pointAt(progress), value);
194         return value;
195     }
196 
197     template<typename T>
peek(uint32_t time) const198     T tween<T>::peek(uint32_t time) const {
199         T value;
200         float progress = static_cast<float>(time) / static_cast<float>(total);
201         interpolate(progress, pointAt(progress), value);
202         return value;
203     }
204 
205 
206   template<typename T>
progress() const207     float tween<T>::progress() const {
208         return currentProgress;
209     }
210 
211     template<typename T>
forward()212     tween<T> & tween<T>::forward() {
213         currentDirection = 1;
214         return *this;
215     }
216 
217     template<typename T>
backward()218     tween<T> & tween<T>::backward() {
219         currentDirection = -1;
220         return *this;
221     }
222 
223     template<typename T>
direction() const224     int tween<T>::direction() const {
225         return currentDirection;
226     }
227 
228     template<typename T>
jump(int32_t p,bool suppress)229     inline const T & tween<T>::jump(int32_t p, bool suppress) {
230         p = detail::clip(p, 0, static_cast<int>(points.size() -1));
231         return seek(points.at(p).stacked, suppress);
232     }
233 
point() const234     template<typename T> inline uint16_t tween<T>::point() const {
235         return currentPoint;
236     }
237 
238 
239 
pointAt(float progress) const240     template<typename T> inline uint16_t tween<T>::pointAt(float progress) const {
241         uint32_t t = static_cast<uint32_t>(progress * total);
242         uint16_t point = 0;
243         while (t > points.at(point).stacked) point++;
244         if (point > 0 && t <= points.at(point - 1u).stacked) point--;
245         return point;
246     }
247 }
248 #endif //TWEENY_TWEENONE_TCC
249