raycaster/tests/animation2.cpp

117 lines
2.5 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <fmt/core.h>
#include <string>
#include <coroutine>
#include <chrono>
#include "rand.hpp"
#include <thread>
#include <vector>
#include "components.hpp"
#include <iostream>
#include "stats.hpp"
#include "simplefsm.hpp"
#include "textures.hpp"
#include "animation.hpp"
using namespace std::chrono_literals;
using components::Animation;
using TheClock = std::chrono::steady_clock;
using TimeDelta = TheClock::duration;
using TimePoint = std::chrono::time_point<TheClock>;
const TimeDelta MIN_TICK = 200ms;
struct AnimationState {
Animation anim;
TimeDelta wait = 1s;
sf::Vector2f scale{1.0, 1.0};
sf::Vector2f pos{0.0, 0.0};
sf::IntRect rect{{0, 0}, {300, 300}};
void step() {
anim.step(scale, pos, rect);
}
void apply(textures::SpriteTexture& st) {
animation::apply(anim, *st.sprite, pos);
}
};
struct AnimationQueue {
std::vector<AnimationState> active;
TimePoint last_tick;
TimeDelta wait_for = MIN_TICK;
size_t in_queue = 0;
size_t chunk = 1000;
TimeDelta delta() {
return TheClock::now() - last_tick;
}
void tick() {
last_tick = TheClock::now();
}
size_t add(Animation& anim, int initial_wait) {
active.emplace_back(anim, TheClock::duration(initial_wait));
return active.size() - 1;
}
AnimationState& get(size_t id) {
return active.at(id);
}
void render() {
wait_for = MIN_TICK;
auto dt = delta();
for(size_t i = 0; i < chunk; i++) {
in_queue++;
auto& a = active[in_queue % active.size()];
if(!a.anim.playing) continue;
if(a.wait < wait_for) {
wait_for = a.wait;
}
if(a.wait < dt) {
// fmt::println("play animation: {} total ", active.size());
a.step();
}
}
}
};
TEST_CASE("simple coroutine animation test", "[coro]") {
AnimationQueue queue;
Animation anim;
anim.play();
for(int i = 0; i < 100; i++) {
int time = Random::uniform(16, 32);
size_t id = queue.add(anim, time);
auto& what = queue.get(id);
REQUIRE(what.wait == TheClock::duration(time));
}
dbc::check(queue.active.size() > 0, "zero size queue after adding is impossible.");
queue.tick();
Stats stats;
for(int i = 0; i < 10000; i++) {
auto start = stats.time_start();
auto delta = queue.delta();
queue.render();
if(delta > queue.wait_for) {
queue.add(anim, Random::uniform(100, 5000));
queue.tick();
}
stats.sample_time(start);
}
fmt::print("stdev: {}, mean: {}\r", stats.stddev(), stats.mean());
}