351 fabric::tasks::executor::sptr executor_;
352 std::atomic_flag enabled_{
false};
353 std::atomic_flag stop_flag_{
false};
356 fabric::wiring::output_signal<AnimationSystem, components::component_base_t::sptr>
s_repaint{};
361 : executor_(executor) {}
364 if (enabled_.test_and_set()) {
369 executor_->schedule([&] -> fabric::task<> {
370 while (not this->stop_flag_.test()) {
378 if (not enabled_.test()) {
381 stop_flag_.test_and_set();
387 ZoneScopedN(
"AnimationSystem");
388 auto now = std::chrono::system_clock::now();
390 std::forward_list<components::component_base_t::sptr> c_pending_compose{};
391 std::forward_list<components::component_base_t::sptr> c_pending_repaint{};
392 std::forward_list<components::component_base_t::sptr> c_pending_reflow{};
393 std::forward_list<components::component_base_t::sptr> c_pending_full_update{};
394 std::forward_list<components::component_base_t::sptr> c_pending_deanimation{};
397 ZoneScopedN(
"advance");
398 for (
auto anim = active_animations_.begin(); anim != active_animations_.end();) {
399 switch (anim->complexity) {
401 c_pending_reflow.push_front(anim->component.lock());
404 c_pending_repaint.push_front(anim->component.lock());
407 c_pending_compose.push_front(anim->component.lock());
410 c_pending_full_update.push_front(anim->component.lock());
414 if (not advance_animation(anim, now)) {
415 c_pending_deanimation.push_front(anim->component.lock());
416 anim = active_animations_.erase(anim);
425 for (
const auto& c: c_pending_deanimation) {
429 bool needs_compositing =
false;
434 if (not c_pending_repaint.empty()) {
435 for (
const auto& c: c_pending_repaint) {
442 if (not c_pending_compose.empty() or needs_compositing) {
446 if (active_animations_.empty()) {
456 active_animations_.push_back(make_animation_state(anim, component));
463 animation_state state{anim, component, std::chrono::system_clock::now()};
465 const refl::type_info& style_ti = component->get_style_type_info();
467 for (
const auto& [prop_id, prop_timeline]: anim.data_->timelines_) {
468 auto& [type_id, prop_name] = prop_id;
470 for (
const auto& field_ti: style_ti.fields()) {
471 if (field_ti.type().id() == type_id and field_ti.name == prop_name) {
474 void* field_ptr = field_ti.get_ptr(component->get_style_data().as_raw());
475 refl::any initial_value = refl::any::make(field_ti.type(), field_ptr);
477 state.property_map[prop_id] = {&field_ti, initial_value};
478 if (complexity > state.complexity) {
479 state.complexity = complexity;
490 bool advance_animation(
491 std::list<animation_state>::iterator& anim, std::chrono::system_clock::time_point now
493 auto x = (now - anim->started).count()
494 /
static_cast<float>(anim->anim.data_->options_.duration_.count());
495 x = anim->anim.data_->options_.easing_function_(x);
497 const bool is_complete = x > 1.0;
498 if (is_complete or anim->component.expired()) {
499 if (not anim->component.expired()) {
500 apply_animation_frame(anim, 1.0);
505 apply_animation_frame(anim, x);
509 void apply_animation_frame(std::list<animation_state>::iterator& anim,
float frame_x) {
510 auto component = anim->component.lock();
511 for (
const auto& [prop_id, prop_info]: anim->property_map) {
512 const auto& [field_info, initial_value] = prop_info;
513 auto& prop_timeline = anim->anim.data_->timelines_.at(prop_id);
515 refl::any interpolated_value = prop_timeline.interpolate(frame_x, initial_value);
516 void* field_ptr = field_info->get_ptr(component->get_style_data().as_raw());
517 field_info->type().assign_copy_of(interpolated_value.data(), field_ptr);
522 std::list<animation_state> active_animations_{};