From 8ec358afb0c86dadc9f77d5b8f449cd3443b1186 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 2 Sep 2019 07:00:07 +0700 Subject: [PATCH] two separated spine system for pre and post update --- headers/enduro2d/high/_all.hpp | 2 +- headers/enduro2d/high/_high.hpp | 3 +- .../{spine_system.hpp => spine_systems.hpp} | 16 +- sources/enduro2d/high/starter.cpp | 11 +- .../high/systems/spine_post_system.cpp | 237 ++++++++++++++++++ .../high/systems/spine_pre_system.cpp | 62 +++++ .../enduro2d/high/systems/spine_system.cpp | 199 --------------- 7 files changed, 321 insertions(+), 209 deletions(-) rename headers/enduro2d/high/systems/{spine_system.hpp => spine_systems.hpp} (57%) create mode 100644 sources/enduro2d/high/systems/spine_post_system.cpp create mode 100644 sources/enduro2d/high/systems/spine_pre_system.cpp delete mode 100644 sources/enduro2d/high/systems/spine_system.cpp diff --git a/headers/enduro2d/high/_all.hpp b/headers/enduro2d/high/_all.hpp index 109ea471..9b884826 100644 --- a/headers/enduro2d/high/_all.hpp +++ b/headers/enduro2d/high/_all.hpp @@ -43,7 +43,7 @@ #include "systems/flipbook_system.hpp" #include "systems/label_system.hpp" #include "systems/render_system.hpp" -#include "systems/spine_system.hpp" +#include "systems/spine_systems.hpp" #include "address.hpp" #include "asset.hpp" diff --git a/headers/enduro2d/high/_high.hpp b/headers/enduro2d/high/_high.hpp index ec5b45df..c21f251a 100644 --- a/headers/enduro2d/high/_high.hpp +++ b/headers/enduro2d/high/_high.hpp @@ -55,7 +55,8 @@ namespace e2d class flipbook_system; class label_system; class render_system; - class spine_system; + class spine_pre_system; + class spine_post_system; template < typename Asset, typename Content > class content_asset; diff --git a/headers/enduro2d/high/systems/spine_system.hpp b/headers/enduro2d/high/systems/spine_systems.hpp similarity index 57% rename from headers/enduro2d/high/systems/spine_system.hpp rename to headers/enduro2d/high/systems/spine_systems.hpp index 0bdefa68..c13844a8 100644 --- a/headers/enduro2d/high/systems/spine_system.hpp +++ b/headers/enduro2d/high/systems/spine_systems.hpp @@ -10,10 +10,20 @@ namespace e2d { - class spine_system final : public ecs::system { + class spine_pre_system final : public ecs::system { public: - spine_system(); - ~spine_system() noexcept final; + spine_pre_system(); + ~spine_pre_system() noexcept final; + void process(ecs::registry& owner) override; + private: + class internal_state; + std::unique_ptr state_; + }; + + class spine_post_system final : public ecs::system { + public: + spine_post_system(); + ~spine_post_system() noexcept final; void process(ecs::registry& owner) override; private: class internal_state; diff --git a/sources/enduro2d/high/starter.cpp b/sources/enduro2d/high/starter.cpp index e0c082c1..0209143f 100644 --- a/sources/enduro2d/high/starter.cpp +++ b/sources/enduro2d/high/starter.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include namespace { @@ -46,10 +46,11 @@ namespace bool initialize() final { ecs::registry_filler(the().registry()) - .system(world::priority_update) - .system(world::priority_update) - .system(world::priority_render) - .system(world::priority_update); + .system(world::priority_pre_update) + .system(world::priority_pre_update) + .system(world::priority_pre_update) + .system(world::priority_post_update) + .system(world::priority_render); return !application_ || application_->initialize(); } diff --git a/sources/enduro2d/high/systems/spine_post_system.cpp b/sources/enduro2d/high/systems/spine_post_system.cpp new file mode 100644 index 00000000..28fea236 --- /dev/null +++ b/sources/enduro2d/high/systems/spine_post_system.cpp @@ -0,0 +1,237 @@ +/******************************************************************************* + * This file is part of the "Enduro2D" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include + +#include +#include +#include + +#include + +namespace +{ + using namespace e2d; + + struct entry_internal_state { + ecs::entity target; + str end_message; + str complete_message; + + entry_internal_state(ecs::entity target, str end_msg, str complete_msg) + : target(std::move(target)) + , end_message(std::move(end_msg)) + , complete_message(std::move(complete_msg)) {} + }; + + void entry_listener( + spAnimationState*, + spEventType type, + spTrackEntry* entry, + spEvent* event) + { + if ( !entry->userData ) { + return; + } + + entry_internal_state& entry_state = + *static_cast(entry->userData); + + if ( type == SP_ANIMATION_DISPOSE || !entry_state.target.valid() ) { + std::unique_ptr entry_internal(&entry_state); + entry->userData = nullptr; + return; + } + + if ( type == SP_ANIMATION_EVENT ) { + if ( !event || !event->data ) { + return; + } + entry_state.target.ensure_component() + .add_event(spine_player_evt::custom_evt(event->data->name ? event->data->name : "") + .int_value(event->intValue) + .float_value(event->floatValue) + .string_value(event->stringValue ? event->stringValue : "")); + } else if ( type == SP_ANIMATION_END ) { + if ( entry_state.end_message.empty() ) { + return; + } + entry_state.target.ensure_component() + .add_event(spine_player_evt::end_evt(entry_state.end_message)); + } else if ( type == SP_ANIMATION_COMPLETE ) { + if ( entry_state.complete_message.empty() ) { + return; + } + entry_state.target.ensure_component() + .add_event(spine_player_evt::complete_evt(entry_state.complete_message)); + } + } + + class command_visitor final : private noncopyable { + public: + command_visitor( + ecs::entity target, + spSkeletonData& skeleton_data, + spAnimationState& animation_state) + : target_(std::move(target)) + , skeleton_data_(skeleton_data) + , animation_state_(animation_state) {} + + void operator()(const spine_player_cmd::clear_track_cmd& cmd) const noexcept { + spAnimationState_clearTrack( + &animation_state_, + math::numeric_cast(cmd.track())); + } + + void operator()(const spine_player_cmd::set_anim_cmd& cmd) const noexcept { + spAnimation* animation = spSkeletonData_findAnimation(&skeleton_data_, cmd.name().c_str()); + if ( !animation ) { + the().error("SPINE_POST_SYSTEM: animation '%0' is not found", cmd.name()); + return; + } + + auto entry_state = std::make_unique( + target_, + cmd.end_message(), + cmd.complete_message()); + + spTrackEntry* entry = spAnimationState_setAnimation( + &animation_state_, + math::numeric_cast(cmd.track()), + animation, + cmd.loop() ? 1 : 0); + + entry->listener = &entry_listener; + entry->userData = entry_state.release(); + } + + void operator()(const spine_player_cmd::add_anim_cmd& cmd) const noexcept { + spAnimation* animation = spSkeletonData_findAnimation(&skeleton_data_, cmd.name().c_str()); + if ( !animation ) { + the().error("SPINE_POST_SYSTEM: animation '%0' is not found", cmd.name()); + return; + } + + auto entry_state = std::make_unique( + target_, + cmd.end_message(), + cmd.complete_message()); + + spTrackEntry* entry = spAnimationState_addAnimation( + &animation_state_, + math::numeric_cast(cmd.track()), + animation, + cmd.loop() ? 1 : 0, + cmd.delay().value); + + entry->listener = &entry_listener; + entry->userData = entry_state.release(); + } + + void operator()(const spine_player_cmd::set_empty_anim_cmd& cmd) const noexcept { + auto entry_state = std::make_unique( + target_, + cmd.end_message(), + cmd.complete_message()); + + spTrackEntry* entry = spAnimationState_setEmptyAnimation( + &animation_state_, + math::numeric_cast(cmd.track()), + cmd.mix_duration().value); + + entry->listener = &entry_listener; + entry->userData = entry_state.release(); + } + + void operator()(const spine_player_cmd::add_empty_anim_cmd& cmd) const noexcept { + auto entry_state = std::make_unique( + target_, + cmd.end_message(), + cmd.complete_message()); + + spTrackEntry* entry = spAnimationState_addEmptyAnimation( + &animation_state_, + math::numeric_cast(cmd.track()), + cmd.mix_duration().value, + cmd.delay().value); + + entry->listener = &entry_listener; + entry->userData = entry_state.release(); + } + private: + ecs::entity target_; + spSkeletonData& skeleton_data_; + spAnimationState& animation_state_; + }; +} + +namespace e2d +{ + // + // internal_state + // + + class spine_post_system::internal_state final { + public: + internal_state() = default; + ~internal_state() noexcept = default; + + void process(ecs::registry& owner) { + process_commands(owner); + clear_commands(owner); + clear_events(owner); + } + private: + void process_commands(ecs::registry& owner) { + owner.for_joined_components([]( + ecs::entity e, + const spine_player_cmd& pc, + spine_player& p) + { + spSkeleton* skeleton = p.skeleton().get(); + spAnimationState* animation_state = p.animation().get(); + + if ( !skeleton || !skeleton->data || !animation_state ) { + return; + } + + command_visitor v(e, *skeleton->data, *animation_state); + for ( const auto& cmd : pc.commands() ) { + stdex::visit(v, cmd); + } + }); + } + + void clear_commands(ecs::registry& owner) { + owner.for_each_component([ + ](const ecs::const_entity&, spine_player_cmd& pc) { + pc.clear_commands(); + }); + } + + void clear_events(ecs::registry& owner) { + owner.for_each_component([ + ](const ecs::const_entity&, spine_player_evt& pe) { + pe.clear_events(); + }); + } + }; + + // + // spine_post_system + // + + spine_post_system::spine_post_system() + : state_(new internal_state()) {} + + spine_post_system::~spine_post_system() noexcept { + spAnimationState_disposeStatics(); + } + + void spine_post_system::process(ecs::registry& owner) { + state_->process(owner); + } +} diff --git a/sources/enduro2d/high/systems/spine_pre_system.cpp b/sources/enduro2d/high/systems/spine_pre_system.cpp new file mode 100644 index 00000000..16c26d0e --- /dev/null +++ b/sources/enduro2d/high/systems/spine_pre_system.cpp @@ -0,0 +1,62 @@ +/******************************************************************************* + * This file is part of the "Enduro2D" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include + +#include +#include +#include + +#include + +namespace e2d +{ + // + // internal_state + // + + class spine_pre_system::internal_state final { + public: + internal_state() = default; + ~internal_state() noexcept = default; + + void process(ecs::registry& owner) { + update_animations(owner); + } + private: + void update_animations(ecs::registry& owner) { + const float dt = the().delta_time(); + owner.for_each_component([dt]( + const ecs::const_entity&, + spine_player& p) + { + spSkeleton* skeleton = p.skeleton().get(); + spAnimationState* anim_state = p.animation().get(); + + if ( !skeleton || !anim_state ) { + return; + } + + spSkeleton_update(skeleton, dt); + spAnimationState_update(anim_state, dt); + spAnimationState_apply(anim_state, skeleton); + spSkeleton_updateWorldTransform(skeleton); + }); + } + }; + + // + // spine_pre_system + // + + spine_pre_system::spine_pre_system() + : state_(new internal_state()) {} + spine_pre_system::~spine_pre_system() noexcept = default; + + void spine_pre_system::process(ecs::registry& owner) { + state_->process(owner); + } +} diff --git a/sources/enduro2d/high/systems/spine_system.cpp b/sources/enduro2d/high/systems/spine_system.cpp deleted file mode 100644 index 56884c62..00000000 --- a/sources/enduro2d/high/systems/spine_system.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/******************************************************************************* - * This file is part of the "Enduro2D" - * For conditions of distribution and use, see copyright notice in LICENSE.md - * Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com) - ******************************************************************************/ - -#include - -#include -#include - -#include - -namespace -{ - // spine will allocate storage for each track, so keep number of track as small as possible - constexpr e2d::u32 max_track_count = 8; -} - -namespace e2d -{ - // - // internal_state - // - - class spine_system::internal_state final { - public: - void clear_events(ecs::registry& owner) const; - void process_new_animations(ecs::registry& owner); - void update_animations(ecs::registry& owner); - - void add_event(spTrackEntry* entry, const str& ev_name); - private: - struct animation_visitor_; - static void event_listener_(spAnimationState* state, spEventType type, spTrackEntry* entry, spEvent* event); - private: - flat_map anim_events_; - ecs::registry* owner_ = nullptr; - }; - - // - // animation_visitor_ - // - - struct spine_system::internal_state::animation_visitor_ { - animation_visitor_( - spSkeletonData* skeleton, - spAnimationState* anim_state, - internal_state& state) - : skeleton_(skeleton) - , anim_state_(anim_state) - , state_(state) {} - - void operator()(const spine_animation_event::clear_track& cmd) const noexcept { - E2D_ASSERT(cmd.track < max_track_count); - spAnimationState_clearTrack(anim_state_, cmd.track); - } - - void operator()(const spine_animation_event::set_anim& cmd) const noexcept { - E2D_ASSERT(cmd.track < max_track_count); - - spAnimation* anim = spSkeletonData_findAnimation(skeleton_, cmd.name.c_str()); - if ( !anim ) { - the().error("SPINE_PLAYER: animation '%0' is not found", cmd.name); - return; - } - spTrackEntry* entry = spAnimationState_setAnimation(anim_state_, cmd.track, anim, cmd.loop); - if ( entry && !cmd.on_complete.empty() ) { - state_.add_event(entry, cmd.on_complete); - } - } - - void operator()(const spine_animation_event::add_anim& cmd) const noexcept { - E2D_ASSERT(cmd.track < max_track_count); - - spAnimation* anim = spSkeletonData_findAnimation(skeleton_, cmd.name.c_str()); - if ( !anim ) { - the().error("SPINE_PLAYER: animation '%0' is not found", cmd.name); - return; - } - spTrackEntry* entry = spAnimationState_addAnimation(anim_state_, cmd.track, anim, cmd.loop, cmd.delay.value); - if ( entry && !cmd.on_complete.empty() ) { - state_.add_event(entry, cmd.on_complete); - } - } - - void operator()(const spine_animation_event::empty_anim& cmd) const noexcept { - E2D_ASSERT(cmd.track < max_track_count); - spTrackEntry* entry = spAnimationState_addEmptyAnimation(anim_state_, cmd.track, cmd.duration.value, cmd.delay.value); - if ( entry && !cmd.on_complete.empty() ) { - state_.add_event(entry, cmd.on_complete); - } - } - private: - spSkeletonData* skeleton_; - spAnimationState* anim_state_; - internal_state& state_; - }; - - void spine_system::internal_state::add_event(spTrackEntry* entry, const str& ev_name) { - anim_events_.insert_or_assign(entry, ev_name); - entry->listener = &event_listener_; - entry->userData = this; - } - - void spine_system::internal_state::event_listener_(spAnimationState* state, spEventType type, spTrackEntry* entry, spEvent* event) { - if ( !entry || !entry->userData || type == SP_ANIMATION_DISPOSE ) { - return; - } - - internal_state* self = reinterpret_cast(entry->userData); - auto entry_to_event = self->anim_events_.find(entry); - if ( entry_to_event == self->anim_events_.end() ) { - return; - } - - ecs::entity_id id(size_t(state->userData)); - ecs::entity ent(*self->owner_, id); - - switch ( type ) { - case SP_ANIMATION_COMPLETE: { - auto* comp = ent.find_component(); - if ( !comp ) { - comp = &ent.assign_component(); - } - comp->completed().push_back(std::move(entry_to_event->second)); - - self->anim_events_.erase(entry_to_event); - break; - } - } - } - - void spine_system::internal_state::clear_events(ecs::registry& owner) const { - owner.remove_all_components(); - } - - void spine_system::internal_state::process_new_animations(ecs::registry& owner) { - owner_ = &owner; - owner.for_joined_components( - [this, &owner]( - ecs::entity_id id, - const spine_animation_event& events, - spine_player& player) - { - spSkeleton* skeleton = player.skeleton().get(); - spAnimationState* anim_state = player.animation().get(); - - if ( !skeleton || !anim_state ) { - return; - } - - anim_state->userData = reinterpret_cast(size_t(id)); - - animation_visitor_ vis(skeleton->data, anim_state, *this); - for ( auto& ev : events.commands() ) { - stdex::visit(vis, ev); - } - }); - owner.remove_all_components(); - owner_ = nullptr; - } - - void spine_system::internal_state::update_animations(ecs::registry& owner) { - const float dt = the().delta_time(); - owner_ = &owner; - owner.for_each_component( - [dt]( - ecs::entity_id id, - spine_player& player) - { - spSkeleton* skeleton = player.skeleton().get(); - spAnimationState* anim_state = player.animation().get(); - - if ( !skeleton || !anim_state ) { - return; - } - - spSkeleton_update(skeleton, dt); - spAnimationState_update(anim_state, dt); - spAnimationState_apply(anim_state, skeleton); - spSkeleton_updateWorldTransform(skeleton); - }); - owner_ = nullptr; - } - - spine_system::spine_system() - : state_(new internal_state()) {} - - spine_system::~spine_system() noexcept { - spAnimationState_disposeStatics(); - } - - void spine_system::process(ecs::registry& owner) { - state_->clear_events(owner); - state_->process_new_animations(owner); - state_->update_animations(owner); - } -}