加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
tween.cpp 26.42 KB
一键复制 编辑 原始数据 按行查看 历史
魏兆华 提交于 2021-09-10 16:43 . 补一个注释
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
#include <algorithm>
#include <array>
#include <cstdio>
#include <functional>
#include <tuple>
constexpr auto M_PI = 3.14159265358979323846;
namespace tweeny
{
class easing
{
public:
static constexpr struct steppedEasing
{
template<typename T> static T run(float position, T start, T end) { return start; }
} stepped = steppedEasing{};
static constexpr struct defaultEasing
{
template<class...> struct voidify { using type = void; };
template<class... Ts> using void_t = typename voidify<Ts...>::type;
template<class T, class = void>
struct supports_arithmetic_operations : std::false_type {};
template<class T>
struct supports_arithmetic_operations<T, void_t<
decltype(std::declval<T>() + std::declval<T>()),
decltype(std::declval<T>() - std::declval<T>()),
decltype(std::declval<T>()* std::declval<T>()),
decltype(std::declval<T>()* std::declval<float>()),
decltype(std::declval<float>()* std::declval<T>())
>> : std::true_type{};
template<typename T>
static typename std::enable_if<std::is_integral<T>::value, T>::type run(float position, T start, T end)
{
return static_cast<T>(roundf((end - start) * position + start));
}
template<typename T>
static typename std::enable_if<supports_arithmetic_operations<T>::value && !std::is_integral<T>::value, T>::type run(float position, T start, T end)
{
return static_cast<T>((end - start) * position + start);
}
template<typename T>
static typename std::enable_if<!supports_arithmetic_operations<T>::value, T>::type run(float position, T start, T end)
{
return start;
}
} def = defaultEasing{};
static constexpr struct linearEasing
{
template<typename T>
static typename std::enable_if<std::is_integral<T>::value, T>::type run(float position, T start, T end)
{
return static_cast<T>(roundf((end - start) * position + start));
}
template<typename T>
static typename std::enable_if<!std::is_integral<T>::value, T>::type run(float position, T start, T end)
{
return static_cast<T>((end - start) * position + start);
}
} linear = linearEasing{};
static constexpr struct quadraticInEasing
{
template<typename T>
static T run(float position, T start, T end) { return static_cast<T>((end - start) * position * position + start); }
} quadraticIn = quadraticInEasing{};
static constexpr struct quadraticOutEasing
{
template<typename T>
static T run(float position, T start, T end) { return static_cast<T>((-(end - start)) * position * (position - 2) + start); }
} quadraticOut = quadraticOutEasing{};
static constexpr struct quadraticInOutEasing
{
template<typename T>
static T run(float position, T start, T end)
{
position *= 2;
if (position < 1)
return static_cast<T>(((end - start) / 2) * position * position + start);
--position;
return static_cast<T>((-(end - start) / 2) * (position * (position - 2) - 1) + start);
}
} quadraticInOut = quadraticInOutEasing{};
//cubic
//quartic
//quintic
//sinusoidal
//exponential
//circular
//bounce
//elastic
//back
}; //class easing
template<typename T, typename... Ts> class tween;
namespace detail
{
template<std::size_t> struct int2type {};
template<int I, typename TypeTuple, typename FunctionTuple, typename... Fs>
struct easingresolve
{
static void impl(FunctionTuple& b, Fs... fs)
{
if (sizeof...(Fs) == 0) return;
easingresolve<I, TypeTuple, FunctionTuple, Fs...>::impl(b, fs...);
}
};
template<int I, typename TypeTuple, typename FunctionTuple, typename F1, typename... Fs>
struct easingresolve<I, TypeTuple, FunctionTuple, F1, Fs...>
{
static void impl(FunctionTuple& b, F1 f1, Fs... fs)
{
std::get<I>(b) = f1;
easingresolve<I + 1, TypeTuple, FunctionTuple, Fs...>::impl(b, fs...);
}
};
template<int I, typename TypeTuple, typename FunctionTuple, typename... Fs>
struct easingresolve<I, TypeTuple, FunctionTuple, easing::steppedEasing, Fs...>
{
typedef typename std::tuple_element<I, TypeTuple>::type ArgType;
static void impl(FunctionTuple& b, easing::steppedEasing, Fs... fs)
{
std::get<I>(b) = easing::stepped.run<ArgType>;
easingresolve<I + 1, TypeTuple, FunctionTuple, Fs...>::impl(b, fs...);
}
};
template<int I, typename TypeTuple, typename FunctionTuple, typename... Fs>
struct easingresolve<I, TypeTuple, FunctionTuple, easing::linearEasing, Fs...>
{
typedef typename std::tuple_element<I, TypeTuple>::type ArgType;
static void impl(FunctionTuple& b, easing::linearEasing, Fs... fs)
{
std::get<I>(b) = easing::linear.run<ArgType>;
easingresolve<I + 1, TypeTuple, FunctionTuple, Fs...>::impl(b, fs...);
}
};
template<int I, typename TypeTuple, typename FunctionTuple, typename... Fs>
struct easingresolve<I, TypeTuple, FunctionTuple, easing::defaultEasing, Fs...>
{
typedef typename std::tuple_element<I, TypeTuple>::type ArgType;
static void impl(FunctionTuple& b, easing::defaultEasing, Fs... fs)
{
std::get<I>(b) = easing::def.run<ArgType>;
easingresolve<I + 1, TypeTuple, FunctionTuple, Fs...>::impl(b, fs...);
}
};
template <int I, typename TypeTuple, typename FunctionTuple, typename... Fs>
struct easingresolve<I, TypeTuple, FunctionTuple, easing::quadraticInEasing, Fs...> {
typedef typename std::tuple_element<I, TypeTuple>::type ArgType;
static void impl(FunctionTuple & b, decltype(easing::quadraticIn), Fs... fs) {
std::get<I>(b) = easing::quadraticIn.run<ArgType>;
easingresolve<I+1, TypeTuple, FunctionTuple, Fs...>::impl(b, fs...);
}
};
template <int I, typename TypeTuple, typename FunctionTuple, typename... Fs>
struct easingresolve<I, TypeTuple, FunctionTuple, easing::quadraticOutEasing, Fs...> {
typedef typename std::tuple_element<I, TypeTuple>::type ArgType;
static void impl(FunctionTuple & b, decltype(easing::quadraticOut), Fs... fs) {
std::get<I>(b) = easing::quadraticOut.run<ArgType>;
easingresolve<I+1, TypeTuple, FunctionTuple, Fs...>::impl(b, fs...);
}
};
template <int I, typename TypeTuple, typename FunctionTuple, typename... Fs>
struct easingresolve<I, TypeTuple, FunctionTuple, easing::quadraticInOutEasing, Fs...>
{
typedef typename std::tuple_element<I, TypeTuple>::type ArgType;
static void impl(FunctionTuple& b, decltype(easing::quadraticInOut), Fs... fs)
{
std::get<I>(b) = easing::quadraticInOut.run<ArgType>;
easingresolve<I + 1, TypeTuple, FunctionTuple, Fs...>::impl(b, fs...);
}
};
//DECLARE_EASING_RESOLVE(cubic);
//DECLARE_EASING_RESOLVE(quartic);
//DECLARE_EASING_RESOLVE(quintic);
//DECLARE_EASING_RESOLVE(sinusoidal);
//DECLARE_EASING_RESOLVE(exponential);
//DECLARE_EASING_RESOLVE(circular);
//DECLARE_EASING_RESOLVE(bounce);
//DECLARE_EASING_RESOLVE(elastic);
//DECLARE_EASING_RESOLVE(back);
//判断类型序列中所有类型是否相同
template<typename... Ts> struct equal {};
template<typename T> struct equal<T> { enum { value = true }; };
template<typename T, typename U, typename... Ts> struct equal<T, U, Ts...>
{
//一定要三个吗?只保留一和三可不可以?
enum { value = std::is_same<T, U>::value && equal<T, Ts...>::value && equal<U, Ts...>::value };
};
//值类型,如果类型都一样就是 std::array<T, n>,否则就是 std::tuple<Ts...>
template<typename T, typename...> struct first { typedef T type; };
template<bool equal, typename... Ts> struct valuetype {};
template<typename... Ts> struct valuetype<false, Ts...> { typedef std::tuple<Ts...> type; };
template<typename... Ts>
struct valuetype<true, Ts...>
{
typedef std::array<typename first<Ts...>::type, sizeof...(Ts)> type;
};
template<typename... Ts>
struct tweentraits
{
typedef std::tuple<std::function<Ts(float, Ts, Ts)>...> easingCollection; //每个类触发函数都是 T(float, T, T)
typedef std::function<bool(tween<Ts...>&, Ts...)> callbackType; //回调 bool(t, Ts...)
typedef std::function<bool(tween<Ts...>&)> noValuesCallbackType; //无值回调 bool(t)
typedef std::function<bool(Ts...)> noTweenCallbackType; //无主回调 bool(Ts...)
typedef typename valuetype<equal<Ts...>::value, Ts...>::type valuesType; //值类型,array 或 tuple
typedef std::array<uint16_t, sizeof...(Ts)> durationsArrayType; //时长,array<uint16_t, n>
typedef tween<Ts...> type;
};
template<typename TypeTupleT, typename EasingCollectionT, typename EasingT>
void easingfill(EasingCollectionT& f, EasingT easing, int2type<0>)
{
easingresolve<0, TypeTupleT, EasingCollectionT, EasingT>::impl(f, easing);
}
//不止一个,就层层解包
template<typename TypeTupleT, typename EasingCollectionT, typename EasingT, size_t I>
void easingfill(EasingCollectionT& f, EasingT easing, int2type<I>)
{
easingresolve<I, TypeTupleT, EasingCollectionT, EasingT>::impl(f, easing);
easingfill<TypeTupleT, EasingCollectionT, EasingT>(f, easing, int2type<I - 1>{ });
}
template<typename... Ts>
struct tweenpoint
{
typedef detail::tweentraits<Ts...> traits;
typename traits::valuesType values; //补间点值,array 或 tuple
typename traits::durationsArrayType durations; //时长,array<uint16_t, n>
typename traits::easingCollection easings; //触发函数,tuple<T(float, T, T)...>
typename traits::callbackType onEnterCallbacks; //回调,bool(t, Ts...)
uint32_t stacked;
tweenpoint(Ts... vs) : values{ vs... }
{
during(static_cast<uint16_t>(0));
via(easing::def);
}
template<typename D> void during(D milis)
{
for (uint16_t& t : durations)
t = static_cast<uint16_t>(milis);
}
template<typename... Ds> void during(Ds... milis)
{
static_assert(sizeof...(Ds) == sizeof...(Ts),
"Amount of durations should be equal to the amount of values in a currentPoint");
std::array<int, sizeof...(Ts)> list = { { milis... } };
std::copy(list.begin(), list.end(), durations.begin());
}
template<typename... Fs> void via(Fs... fs)
{
static_assert(sizeof...(Fs) == sizeof...(Ts),
"Number of functions passed to via() must be equal the number of values.");
detail::easingresolve<0, std::tuple<Ts...>, typename traits::easingCollection, Fs...>::impl(easings, fs...);
}
//超过一个,就逐个解包
template<typename F> void via(F f)
{
easingfill<typename traits::valuesType>(easings, f, int2type<sizeof...(Ts) - 1>{ });
}
uint16_t duration() const { return *std::max_element(durations.begin(), durations.end()); }
uint16_t duration(size_t i) const { return durations.at(i); }
}; //struct tweenpoint
template<typename T>
T clip(const T& n, const T& lower, const T& upper)
{
return std::max(lower, std::min(n, upper));
}
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N - 1, N - 1, S...> {};
template<int ...S> struct gens<0, S...>
{
typedef seq<S...> type;
};
template<typename R, typename Func, typename TupleType, int ...S>
R dispatch(Func&& f, TupleType&& args, seq<S...>)
{
return f(std::get<S>(args) ...);
}
template<typename R, typename Func, typename... Ts>
R call(Func&& f, const std::tuple<Ts...>& args)
{
return dispatch<R>(f, args, typename gens<sizeof...(Ts)>::type());
}
} //namespace detail
template<typename T, typename... Ts>
class tween //补间
{
private:
using traits = detail::tweentraits<T, Ts...>;
uint32_t total = 0;
uint16_t currentPoint = 0;
float currentProgress = 0;
std::vector<detail::tweenpoint<T, Ts...>> points;
typename traits::valuesType current{};
std::vector<typename traits::callbackType> onStepCallbacks;
std::vector<typename traits::callbackType> onSeekCallbacks;
int8_t currentDirection = 1;
private:
tween(T t, Ts... vs) { points.emplace_back(t, vs...); }
//插值 ,逐个解包
template<size_t I>
void interpolate(float prog, unsigned point, typename traits::valuesType& values, detail::int2type<I>) const
{
auto& p = points.at(point);
uint32_t pointDuration = p.duration() - (p.stacked - (prog * static_cast<float>(total)));
float pointTotal = static_cast<float>(pointDuration) / static_cast<float>(p.duration(I));
if (pointTotal > 1.0f) pointTotal = 1.0f;
auto easing = std::get<I>(p.easings);
std::get<I>(values) = easing(pointTotal, std::get<I>(p.values), std::get<I>(points.at(point + 1).values));
interpolate(prog, point, values, detail::int2type<I - 1>{ });
}
void interpolate(float prog, unsigned point, typename traits::valuesType& values, detail::int2type<0>) const
{
auto& p = points.at(point);
uint32_t pointDuration = p.duration() - (p.stacked - (prog * static_cast<float>(total)));
float pointTotal = static_cast<float>(pointDuration) / static_cast<float>(p.duration(0));
if (pointTotal > 1.0f) pointTotal = 1.0f;
auto easing = std::get<0>(p.easings);
std::get<0>(values) = easing(pointTotal, std::get<0>(p.values), std::get<0>(points.at(point + 1).values));
}
void render(float p)
{
currentPoint = pointAt(p);
interpolate(p, currentPoint, current, detail::int2type<sizeof...(Ts) - 1 + 1 /* +1 for the T */>{ });
}
void dispatch(std::vector<typename traits::callbackType>& cbVector)
{
std::vector<size_t> dismissed;
for (size_t i = 0; i < cbVector.size(); ++i) {
auto&& cb = cbVector[i];
bool dismiss = detail::call<bool>(cb, std::tuple_cat(std::make_tuple(std::ref(*this)), current));
if (dismiss) dismissed.push_back(i);
}
if (dismissed.size() > 0) {
for (size_t i = 0; i < dismissed.size(); ++i) {
size_t index = dismissed[i];
cbVector[index] = cbVector.at(cbVector.size() - 1 - i);
}
cbVector.resize(cbVector.size() - dismissed.size());
}
}
uint16_t pointAt(float progress) const
{
uint32_t t = static_cast<uint32_t>(progress * total);
uint16_t point = 0;
while (t > points.at(point).stacked) point++;
if (point > 0 && t <= points.at(point - 1u).stacked) point--;
return point;
}
public:
static tween<T, Ts...> from(T t, Ts... vs) { return tween<T, Ts...>(t, vs...); }
tween() {}
tween<T, Ts...>& to(T t, Ts... vs) { points.emplace_back(t, vs...); return *this; }
template<typename... Fs>
tween<T, Ts...>& via(Fs... fs) { points.at(points.size() - 2).via(fs...); return *this; }
template<typename... Fs>
tween<T, Ts...>& via(int index, Fs... fs) { points.at(static_cast<size_t>(index)).via(fs...); return *this; }
template<typename... Ds>
tween<T, Ts...>& during(Ds... ds)
{
total = 0;
points.at(points.size() - 2).during(ds...);
for (detail::tweenpoint<T, Ts...>& p : points) {
total += p.duration();
p.stacked = total; //各点累计时序
}
return *this;
}
const typename detail::tweentraits<T, Ts...>::valuesType& step(int32_t dt, bool suppressCallbacks = false)
{
return step(static_cast<float>(dt * currentDirection) / static_cast<float>(total), suppressCallbacks);
}
const typename detail::tweentraits<T, Ts...>::valuesType& step(uint32_t dt, bool suppressCallbacks = false)
{
return step(static_cast<int32_t>(dt), suppressCallbacks);
}
const typename detail::tweentraits<T, Ts...>::valuesType& step(float dp, bool suppressCallbacks = false)
{
seek(currentProgress + dp, true);
if (!suppressCallbacks) dispatch(onStepCallbacks);
return current;
}
const typename detail::tweentraits<T, Ts...>::valuesType& seek(float p, bool suppressCallbacks = false)
{
p = detail::clip(p, 0.0f, 1.0f);
currentProgress = p;
render(p);
if (!suppressCallbacks) dispatch(onSeekCallbacks);
return current;
}
const typename detail::tweentraits<T, Ts...>::valuesType& seek(int32_t t, bool suppressCallbacks = false)
{
return seek(static_cast<float>(t) / static_cast<float>(total), suppressCallbacks);
}
const typename detail::tweentraits<T, Ts...>::valuesType& seek(uint32_t t, bool suppressCallbacks = false)
{
return seek(static_cast<float>(t) / static_cast<float>(total), suppressCallbacks);
}
tween<T, Ts...>& onStep(typename detail::tweentraits<T, Ts...>::callbackType callback)
{
onStepCallbacks.push_back(callback);
return *this;
}
tween<T, Ts...>& onStep(typename detail::tweentraits<T, Ts...>::noValuesCallbackType callback)
{
onStepCallbacks.push_back([callback](tween<T, Ts...>& t, T, Ts...) { return callback(t); });
return *this;
}
tween<T, Ts...>& onStep(typename detail::tweentraits<T, Ts...>::noTweenCallbackType callback)
{
onStepCallbacks.push_back([callback](tween<T, Ts...>&, T t, Ts... vs) { return callback(t, vs...); });
return *this;
}
tween<T, Ts...>& onSeek(typename detail::tweentraits<T, Ts...>::callbackType callback)
{
onSeekCallbacks.push_back(callback);
return *this;
}
tween<T, Ts...>& onSeek(typename detail::tweentraits<T, Ts...>::noValuesCallbackType callback)
{
onSeekCallbacks.push_back([callback](tween<T, Ts...>& t, T, Ts...) { return callback(t); });
return *this;
}
tween<T, Ts...>& onSeek(typename detail::tweentraits<T, Ts...>::noTweenCallbackType callback)
{
onSeekCallbacks.push_back([callback](tween<T, Ts...>&, T t, Ts... vs) { return callback(t, vs...); });
return *this;
}
uint32_t duration() const { return total; }
const typename detail::tweentraits<T, Ts...>::valuesType& peek() const { return current; }
const typename detail::tweentraits<T, Ts...>::valuesType peek(float progress) const
{
typename detail::tweentraits<T, Ts...>::valuesType values;
interpolate(progress, pointAt(progress), values, detail::int2type<sizeof...(Ts) - 1 + 1 /* +1 for the T */>{ });
return values;
}
const typename detail::tweentraits<T, Ts...>::valuesType peek(uint32_t time) const
{
typename detail::tweentraits<T, Ts...>::valuesType values;
float progress = static_cast<float>(time) / static_cast<float>(total);
interpolate(progress, pointAt(progress), values, detail::int2type<sizeof...(Ts) - 1 + 1 /* +1 for the T */>{ });
return values;
}
uint16_t point() const { return currentPoint; }
float progress() const { return currentProgress; }
int direction() const { return currentDirection; }
tween<T, Ts...>& forward() { currentDirection = 1; return *this; }
tween<T, Ts...>& backward() { currentDirection = -1; return *this; }
const typename detail::tweentraits<T, Ts...>::valuesType& jump(int32_t point, bool suppressCallbacks = false)
{
point = detail::clip(point, 0, points.size() - 1);
return seek(points.at(point).stacked, suppressCallbacks);
}
}; //class tween
//其实这个单参数类,完全可以不要
template<typename T>
class tween<T>
{
private:
using traits = detail::tweentraits<T>;
uint32_t total = 0;
uint16_t currentPoint = 0;
float currentProgress = 0;
std::vector<detail::tweenpoint<T>> points;
T current{};
std::vector<typename traits::callbackType> onStepCallbacks;
std::vector<typename traits::callbackType> onSeekCallbacks;
int8_t currentDirection = 1;
tween(T t) { points.emplace_back(t); }
void interpolate(float prog, unsigned point, T& value) const
{
auto& p = points.at(point);
auto pointDuration = p.duration() - (p.stacked - (prog * static_cast<float>(total)));
float pointTotal = static_cast<float>(pointDuration) / static_cast<float>(p.duration());
if (pointTotal > 1.0f) pointTotal = 1.0f;
auto easing = std::get<0>(p.easings);
value = easing(pointTotal, std::get<0>(p.values), std::get<0>(points.at(point + 1).values));
}
void render(float p)
{
currentPoint = pointAt(p);
interpolate(p, currentPoint, current);
}
void dispatch(std::vector<typename traits::callbackType>& cbVector)
{
std::vector<size_t> dismissed;
for (size_t i = 0; i < cbVector.size(); ++i) {
auto&& cb = cbVector[i];
bool dismiss = cb(*this, current);
if (dismiss) dismissed.push_back(i);
}
if (dismissed.size() > 0) {
for (size_t i = 0; i < dismissed.size(); ++i) {
size_t index = dismissed[i];
cbVector[index] = cbVector.at(cbVector.size() - 1 - i);
}
cbVector.resize(cbVector.size() - dismissed.size());
}
}
uint16_t pointAt(float progress) const
{
uint32_t t = static_cast<uint32_t>(progress * total);
uint16_t point = 0;
while (t > points.at(point).stacked) point++;
if (point > 0 && t <= points.at(point - 1u).stacked) point--;
return point;
}
public:
static tween<T> from(T t) { return tween<T>(t); }
tween() {}
tween<T>& to(T t) { points.emplace_back(t); return *this; }
template<typename... Fs> tween<T>& via(Fs... fs)
{
points.at(points.size() - 2).via(fs...);
return *this;
}
template<typename... Fs> tween<T>& via(int index, Fs... fs)
{
points.at(static_cast<size_t>(index)).via(fs...);
return *this;
}
template<typename... Ds> tween<T>& during(Ds... ds)
{
total = 0;
points.at(points.size() - 2).during(ds...); //如果小于2,会抛出异常
for (detail::tweenpoint<T>& p : points) {
total += p.duration();
p.stacked = total;
}
return *this;
}
const T& step(int32_t dt, bool suppressCallbacks = false)
{
return step(static_cast<float>(dt * currentDirection) / static_cast<float>(total), suppressCallbacks);
}
const T& step(uint32_t dt, bool suppressCallbacks = false)
{
return step(static_cast<int32_t>(dt), suppressCallbacks);
}
const T& step(float dp, bool suppressCallbacks = false)
{
seek(currentProgress + dp, true);
if (!suppressCallbacks) dispatch(onStepCallbacks);
return current;
}
const T& seek(float p, bool suppressCallbacks = false)
{
p = detail::clip(p, 0.0f, 1.0f);
currentProgress = p;
render(p);
if (!suppressCallbacks) dispatch(onSeekCallbacks);
return current;
}
const T& seek(int32_t t, bool suppressCallbacks = false)
{
return seek(static_cast<float>(t) / static_cast<float>(total), suppressCallbacks);
}
const T& seek(uint32_t t, bool suppressCallbacks = false)
{
return seek(static_cast<float>(t) / static_cast<float>(total), suppressCallbacks);
}
tween<T>& onStep(typename detail::tweentraits<T>::callbackType callback)
{
onStepCallbacks.push_back(callback);
return *this;
}
tween<T>& onStep(typename detail::tweentraits<T>::noValuesCallbackType callback)
{
onStepCallbacks.push_back([callback](tween<T>& tween, T) { return callback(tween); });
return *this;
}
tween<T>& onStep(typename detail::tweentraits<T>::noTweenCallbackType callback)
{
onStepCallbacks.push_back([callback](tween<T>&, T v) { return callback(v); });
return *this;
}
tween<T>& onSeek(typename detail::tweentraits<T>::callbackType callback)
{
onSeekCallbacks.push_back(callback);
return *this;
}
tween<T>& onSeek(typename detail::tweentraits<T>::noValuesCallbackType callback)
{
onSeekCallbacks.push_back([callback](tween<T>& t, T) { return callback(t); });
return *this;
}
tween<T>& onSeek(typename detail::tweentraits<T>::noTweenCallbackType callback)
{
onSeekCallbacks.push_back([callback](tween<T>&, T v) { return callback(v); });
return *this;
}
const T& peek() const { return current; }
T peek(float progress) const
{
T value;
interpolate(progress, pointAt(progress), value);
return value;
}
T peek(uint32_t time) const
{
T value;
float progress = static_cast<float>(time) / static_cast<float>(total);
interpolate(progress, pointAt(progress), value);
return value;
}
uint32_t duration() const { return total; }
float progress() const { return currentProgress; }
int direction() const { return currentDirection; }
uint16_t point() const { return currentPoint; }
tween<T>& forward() { currentDirection = 1; return *this; }
tween<T>& backward() { currentDirection = -1; return *this; }
const T& jump(int32_t point, bool suppressCallbacks = false)
{
point = detail::clip(point, 0, static_cast<int>(points.size() - 1));
return seek(points.at(point).stacked, suppressCallbacks);
}
}; //class tween one
template<typename... Ts> tween<Ts...> from(Ts... vs)
{
return tween<Ts...>::from(vs...);
}
} //namespace tweeny
template<typename EasingT> void test(tweeny::tween<int>& tween, EasingT easing)
{
tween.via(0, easing);
tween.seek(0);
for (int i = 0; i <= 50; i++)
tween.step(0.02f);
}
bool print(tweeny::tween<int>&, int p)
{
printf("%+.3d |", p); // 3 digits with sign
for (int i = 0; i <= 100; i++) printf("%c", i == p ? '.' : ' '); // prints the line
printf("%c\n", p == 100 ? ';' : '|');
return false;
}
int main()
{
auto t = tweeny::from(0).to(100).during(100).onStep(print);
printf("tweeny::easing::linear\n");
test(t, tweeny::easing::linear);
int c = getchar();
printf("%s\n", "tweeny::easing::quadratic In/Out/InOut");
test(t, tweeny::easing::quadraticIn);
test(t, tweeny::easing::quadraticOut);
test(t, tweeny::easing::quadraticInOut);
//EASING_TEST(t, tweeny::easing::cubic);
//EASING_TEST(t, tweeny::easing::quartic);
//EASING_TEST(t, tweeny::easing::quintic);
//EASING_TEST(t, tweeny::easing::sinusoidal);
//EASING_TEST(t, tweeny::easing::exponential);
//EASING_TEST(t, tweeny::easing::circular);
//EASING_TEST(t, tweeny::easing::bounce);
//EASING_TEST(t, tweeny::easing::elastic);
//EASING_TEST(t, tweeny::easing::back);
return 0;
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化