/* Crafter®.Graphics Copyright (C) 2025 Catcrafts® Catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ export module Crafter.Graphics:Animation; import std; namespace Crafter { template constexpr T Lerp(T a, T b, double elapsed) { return a + static_cast(elapsed * (b - a)); } // Template specialization for std::string template <> std::string Lerp(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::floor(b.size() * elapsed)); return a + b.substr(0, len); } template constexpr auto LerpTupleImpl(const Tuple& a, const Tuple& b, double elapsed, std::index_sequence) { return std::make_tuple(Lerp(std::get(a), std::get(b), elapsed)...); } template constexpr auto LerpTuple(const Tuple& a, const Tuple& b, double elapsed) { return LerpTupleImpl(a, b, elapsed, std::make_index_sequence>{}); } export template struct Keyframe{ std::chrono::duration duration; T startValues; T endValues; }; export template struct Animation { std::vector> keyframes; std::uint_fast32_t currentFrame; std::chrono::time_point startedAt; Animation(std::vector>&& keyframes) : keyframes(std::move(keyframes)) {} void Start(std::chrono::time_point time) { currentFrame = 0; startedAt = time; } T Play(std::chrono::time_point time) { std::chrono::duration elapsed = time - startedAt; std::chrono::duration accumulated(0); for (std::uint_fast32_t i = currentFrame; i < keyframes.size(); ++i) { accumulated += keyframes[i].duration; if (elapsed < accumulated) { std::chrono::duration frameStartTime = accumulated - keyframes[i].duration; auto t = (elapsed - frameStartTime) / keyframes[i].duration.count(); currentFrame = i; return LerpTuple( keyframes[i].startValues, keyframes[i].endValues, t.count() ); } } // If we get here, we're past the last keyframe currentFrame = keyframes.size(); return keyframes.back().endValues; } }; }