Crafter.Graphics/interfaces/Crafter.Graphics-Animation.cppm

78 lines
2.9 KiB
Text
Raw Normal View History

2026-07-22 18:09:06 +02:00
//SPDX-License-Identifier: LGPL-3.0-only
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
2025-11-24 03:38:20 +01:00
export module Crafter.Graphics:Animation;
import std;
namespace Crafter {
template <typename T>
constexpr T Lerp(T a, T b, double elapsed) {
return a + static_cast<T>(elapsed * (b - a));
}
2025-11-24 06:08:35 +01:00
// Template specialization for std::string
template <>
std::string Lerp<std::string>(std::string a, std::string b, double elapsed) {
// Clamp elapsed to [0, 1]
if (elapsed < 0.0) elapsed = 0.0;
if (elapsed > 1.0) elapsed = 1.0;
// Number of characters from b to reveal
std::size_t len = static_cast<std::size_t>(std::floor(b.size() * elapsed));
return a + b.substr(0, len);
}
2025-11-24 03:38:20 +01:00
template <typename Tuple, std::size_t... Is>
constexpr auto LerpTupleImpl(const Tuple& a, const Tuple& b, double elapsed, std::index_sequence<Is...>) {
return std::make_tuple(Lerp(std::get<Is>(a), std::get<Is>(b), elapsed)...);
}
template <typename Tuple>
constexpr auto LerpTuple(const Tuple& a, const Tuple& b, double elapsed) {
return LerpTupleImpl(a, b, elapsed, std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}
export template <typename T>
struct Keyframe{
std::chrono::duration<double> duration;
2025-11-26 00:24:23 +01:00
T startValues;
T endValues;
2025-11-24 03:38:20 +01:00
};
export template <typename T>
struct Animation {
std::vector<Keyframe<T>> keyframes;
std::uint_fast32_t currentFrame;
std::chrono::time_point<std::chrono::high_resolution_clock> startedAt;
2025-11-26 02:56:38 +01:00
std::chrono::duration<double> accumulated;
2025-11-26 00:00:50 +01:00
Animation(std::vector<Keyframe<T>>&& keyframes) : keyframes(std::move(keyframes)) {}
2025-11-24 03:38:20 +01:00
void Start(std::chrono::time_point<std::chrono::high_resolution_clock> time) {
currentFrame = 0;
2025-11-26 02:56:38 +01:00
accumulated = std::chrono::duration<double>(0);
2025-11-24 03:38:20 +01:00
startedAt = time;
}
T Play(std::chrono::time_point<std::chrono::high_resolution_clock> time) {
2025-11-26 00:24:23 +01:00
std::chrono::duration<double> elapsed = time - startedAt;
2025-11-24 03:38:20 +01:00
2025-11-26 02:56:38 +01:00
for (; currentFrame < keyframes.size(); ++currentFrame) {
if (elapsed < accumulated + keyframes[currentFrame].duration) {
std::chrono::duration<double> frameStartTime = accumulated;
auto t = (elapsed - frameStartTime) / keyframes[currentFrame].duration.count();
2025-11-24 03:38:20 +01:00
2025-11-26 00:00:50 +01:00
return LerpTuple(
2025-11-26 02:56:38 +01:00
keyframes[currentFrame].startValues,
keyframes[currentFrame].endValues,
2025-11-24 03:38:20 +01:00
t.count()
);
2025-11-26 02:56:38 +01:00
} else {
accumulated += keyframes[currentFrame].duration;
2025-11-24 03:38:20 +01:00
}
}
// If we get here, we're past the last keyframe
2025-11-26 00:24:23 +01:00
currentFrame = keyframes.size();
return keyframes.back().endValues;
2025-11-24 03:38:20 +01:00
}
};
}