diff --git a/headers/enduro2d/high/components/spine_player.hpp b/headers/enduro2d/high/components/spine_player.hpp index ae2a15a9..c60bd059 100644 --- a/headers/enduro2d/high/components/spine_player.hpp +++ b/headers/enduro2d/high/components/spine_player.hpp @@ -21,16 +21,21 @@ namespace e2d public: spine_player() = default; spine_player(const spine_model_asset::ptr& model); + + spine_player& time_scale(float value) noexcept; + [[nodiscard]] float time_scale() const noexcept; + + [[nodiscard]] bool has_animation(const str& name) const noexcept; - spine_player& set_animation(u32 track, const str& name, bool loop = false); + spine_player& set_animation(u32 track, const str& name, bool loop = false) noexcept; - spine_player& add_animation(u32 track, const str& name, bool loop, secf delay = secf(0.0f)); - spine_player& add_animation(u32 track, const str& name, secf delay = secf(0.0f)); + spine_player& add_animation(u32 track, const str& name, bool loop, secf delay = secf(0.0f)) noexcept; + spine_player& add_animation(u32 track, const str& name, secf delay = secf(0.0f)) noexcept; - spine_player& add_empty_animation(u32 track, secf duration, secf delay = secf(0.0f)); + spine_player& add_empty_animation(u32 track, secf duration, secf delay = secf(0.0f)) noexcept; - spine_player& clear(u32 track); - spine_player& clear(); + spine_player& clear(u32 track) noexcept; + spine_player& clear() noexcept; const animation_ptr& animation() const noexcept; const spine_model_asset::ptr& model() const noexcept; diff --git a/headers/enduro2d/high/components/spine_renderer.hpp b/headers/enduro2d/high/components/spine_renderer.hpp index fcf2d9e2..f7b6ab8d 100644 --- a/headers/enduro2d/high/components/spine_renderer.hpp +++ b/headers/enduro2d/high/components/spine_renderer.hpp @@ -27,9 +27,9 @@ namespace e2d spine_renderer() = default; spine_renderer(const spine_model_asset::ptr& model); - spine_renderer& model(const spine_model_asset::ptr& value); - spine_renderer& skin(const str& value); - spine_renderer& attachment(const str& slot, const str& name); + spine_renderer& model(const spine_model_asset::ptr& value) noexcept; + spine_renderer& skin(const str& value) noexcept; + spine_renderer& attachment(const str& slot, const str& name) noexcept; const skeleton_ptr& skeleton() const noexcept; const clipping_ptr& clipper() const noexcept; diff --git a/headers/enduro2d/high/spine_model.hpp b/headers/enduro2d/high/spine_model.hpp index 70f6a5e9..b82d6d62 100644 --- a/headers/enduro2d/high/spine_model.hpp +++ b/headers/enduro2d/high/spine_model.hpp @@ -40,6 +40,7 @@ namespace e2d spine_model& set_atlas(atlas_ptr atlas, bool premultiplied_alpha); spine_model& mix_animations(const str& from, const str& to, secf duration); + spine_model& set_default_mix(secf duration); const atlas_ptr& atlas() const noexcept; const animation_data_ptr& animation() const noexcept; diff --git a/sources/enduro2d/high/assets/spine_model_asset.cpp b/sources/enduro2d/high/assets/spine_model_asset.cpp index e1bfb2f7..13a05043 100644 --- a/sources/enduro2d/high/assets/spine_model_asset.cpp +++ b/sources/enduro2d/high/assets/spine_model_asset.cpp @@ -32,6 +32,7 @@ namespace "scale" : { "type" : "number" }, "atlas" : { "$ref" : "#/common_definitions/address" }, "premultiplied_alpha" : { "type" : "boolean" }, + "default_mix" : { "type" : "number" }, "mix_animations" : { "$ref": "#/definitions/spine_animation_mix_array" } }, "definitions" : { @@ -193,6 +194,15 @@ namespace content.set_atlas(atlas, pma); content.set_skeleton(skeleton); + secf default_mix(0.0f); + if ( root.HasMember("default_mix") ) { + if ( json_utils::try_parse_value(root["default_mix"], default_mix.value) ) { + content.set_default_mix(default_mix); + } else { + the().error("SPINE: Incorrect formating of 'default_mix' property"); + } + } + if ( root.HasMember("mix_animations") ) { const auto& mix_animations_json = root["mix_animations"]; if ( !parse_mix_animations(mix_animations_json, content) ) { diff --git a/sources/enduro2d/high/components/spine_player.cpp b/sources/enduro2d/high/components/spine_player.cpp index 157232c9..743907f3 100644 --- a/sources/enduro2d/high/components/spine_player.cpp +++ b/sources/enduro2d/high/components/spine_player.cpp @@ -26,7 +26,28 @@ namespace e2d spAnimationState_dispose); } - spine_player& spine_player::set_animation(u32 track, const str& name, bool loop) { + spine_player& spine_player::time_scale(float value) noexcept { + E2D_ASSERT(animation_); + animation_->timeScale = value; + return *this; + } + + float spine_player::time_scale() const noexcept { + E2D_ASSERT(animation_); + return animation_->timeScale; + } + + bool spine_player::has_animation(const str& name) const noexcept { + if ( !model_ ) { + return false; + } + spAnimation* anim = spSkeletonData_findAnimation( + model_->content().skeleton().operator->(), + name.c_str()); + return anim != nullptr; + } + + spine_player& spine_player::set_animation(u32 track, const str& name, bool loop) noexcept { E2D_ASSERT(model_ && animation_); E2D_ASSERT(track < max_track_count); spAnimation* anim = spSkeletonData_findAnimation( @@ -34,18 +55,18 @@ namespace e2d name.c_str()); if ( !anim ) { - E2D_ASSERT(false); // TODO: exception? + the().error("SPINE_PLAYER: animation '%0' is not found", name); return *this; } spAnimationState_setAnimation(animation_.get(), track, anim, loop); return *this; } - spine_player& spine_player::add_animation(u32 track, const str& name, secf delay) { + spine_player& spine_player::add_animation(u32 track, const str& name, secf delay) noexcept { return add_animation(track, name, false, delay); } - spine_player& spine_player::add_animation(u32 track, const str& name, bool loop, secf delay) { + spine_player& spine_player::add_animation(u32 track, const str& name, bool loop, secf delay) noexcept { E2D_ASSERT(model_ && animation_); E2D_ASSERT(track < max_track_count); spAnimation* anim = spSkeletonData_findAnimation( @@ -53,28 +74,28 @@ namespace e2d name.c_str()); if ( !anim ) { - E2D_ASSERT(false); // TODO: exception? + the().error("SPINE_PLAYER: animation '%0' is not found", name); return *this; } spAnimationState_addAnimation(animation_.get(), track, anim, loop, delay.value); return *this; } - spine_player& spine_player::add_empty_animation(u32 track, secf duration, secf delay) { + spine_player& spine_player::add_empty_animation(u32 track, secf duration, secf delay) noexcept { E2D_ASSERT(animation_); E2D_ASSERT(track < max_track_count); spAnimationState_addEmptyAnimation(animation_.get(), track, duration.value, delay.value); return *this; } - spine_player& spine_player::clear(u32 track) { + spine_player& spine_player::clear(u32 track) noexcept { E2D_ASSERT(animation_); E2D_ASSERT(track < max_track_count); spAnimationState_clearTrack(animation_.get(), track); return *this; } - spine_player& spine_player::clear() { + spine_player& spine_player::clear() noexcept { E2D_ASSERT(animation_); spAnimationState_clearTracks(animation_.get()); return *this; diff --git a/sources/enduro2d/high/components/spine_renderer.cpp b/sources/enduro2d/high/components/spine_renderer.cpp index 41f7499b..afbbef13 100644 --- a/sources/enduro2d/high/components/spine_renderer.cpp +++ b/sources/enduro2d/high/components/spine_renderer.cpp @@ -15,7 +15,7 @@ namespace e2d this->model(model); } - spine_renderer& spine_renderer::model(const spine_model_asset::ptr& value) { + spine_renderer& spine_renderer::model(const spine_model_asset::ptr& value) noexcept { E2D_ASSERT(value); E2D_ASSERT(value->content().skeleton()); E2D_ASSERT(value->content().atlas()); @@ -26,15 +26,17 @@ namespace e2d return *this; } - spine_renderer& spine_renderer::skin(const str& value) { + spine_renderer& spine_renderer::skin(const str& value) noexcept { spSkeleton_setSkinByName(skeleton_.get(), value.empty() ? nullptr : value.c_str()); return *this; } - spine_renderer& spine_renderer::attachment(const str& slot, const str& name) { + spine_renderer& spine_renderer::attachment(const str& slot, const str& name) noexcept { E2D_ASSERT(!slot.empty()); E2D_ASSERT(!name.empty()); - spSkeleton_setAttachment(skeleton_.get(), slot.c_str(), name.c_str()); // TODO: check result + if ( !spSkeleton_setAttachment(skeleton_.get(), slot.c_str(), name.c_str()) ) { + the().error("SPINE_RENDERER: can't set attachment '%0' to slot '%1'", name, slot); + } return *this; } diff --git a/sources/enduro2d/high/spine_model.cpp b/sources/enduro2d/high/spine_model.cpp index e1f28b66..0575e647 100644 --- a/sources/enduro2d/high/spine_model.cpp +++ b/sources/enduro2d/high/spine_model.cpp @@ -86,6 +86,12 @@ namespace e2d spAnimationStateData_setMixByName(animation_.get(), from.c_str(), to.c_str(), duration.value); return *this; } + + spine_model& spine_model::set_default_mix(secf duration) { + E2D_ASSERT(animation_); + animation_->defaultMix = duration.value; + return *this; + } const spine_model::atlas_ptr& spine_model::atlas() const noexcept { return atlas_;