mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-14 16:09:06 +07:00
remove spine integration
This commit is contained in:
@@ -14,7 +14,6 @@
|
||||
|
||||
-Imodules/glew/include
|
||||
-Imodules/glfw/include
|
||||
-Imodules/spine/spine-c/spine-c/include
|
||||
|
||||
-std=c++17
|
||||
-stdlib=libc++
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -34,9 +34,6 @@
|
||||
[submodule "modules/flat.hpp"]
|
||||
path = modules/flat.hpp
|
||||
url = https://github.com/BlackMATov/flat.hpp
|
||||
[submodule "modules/spine"]
|
||||
path = modules/spine
|
||||
url = https://github.com/EsotericSoftware/spine-runtimes.git
|
||||
[submodule "modules/enum.hpp"]
|
||||
path = modules/enum.hpp
|
||||
url = https://github.com/BlackMATov/enum.hpp
|
||||
|
||||
@@ -136,9 +136,6 @@ set(glew-cmake_BUILD_MULTI_CONTEXT OFF CACHE INTERNAL "" FORCE)
|
||||
add_subdirectory(modules/glew)
|
||||
set_target_properties(libglew_static PROPERTIES FOLDER modules)
|
||||
|
||||
add_subdirectory(modules/spine/spine-c)
|
||||
set_target_properties(spine-c PROPERTIES FOLDER modules)
|
||||
|
||||
#
|
||||
# e2d library target
|
||||
#
|
||||
@@ -163,7 +160,6 @@ target_link_libraries(${PROJECT_NAME}
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE glfw
|
||||
PRIVATE libglew_static
|
||||
PRIVATE spine-c
|
||||
PRIVATE $<$<CXX_COMPILER_ID:MSVC>:winmm.lib>)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "assets/shader_asset.hpp"
|
||||
#include "assets/shape_asset.hpp"
|
||||
#include "assets/sound_asset.hpp"
|
||||
#include "assets/spine_asset.hpp"
|
||||
#include "assets/sprite_asset.hpp"
|
||||
#include "assets/text_asset.hpp"
|
||||
#include "assets/texture_asset.hpp"
|
||||
@@ -40,7 +39,6 @@
|
||||
#include "components/named.hpp"
|
||||
#include "components/renderer.hpp"
|
||||
#include "components/scene.hpp"
|
||||
#include "components/spine_player.hpp"
|
||||
#include "components/sprite_renderer.hpp"
|
||||
#include "components/touchable.hpp"
|
||||
#include "components/widget.hpp"
|
||||
@@ -49,7 +47,6 @@
|
||||
#include "resources/flipbook.hpp"
|
||||
#include "resources/model.hpp"
|
||||
#include "resources/prefab.hpp"
|
||||
#include "resources/spine.hpp"
|
||||
#include "resources/sprite.hpp"
|
||||
|
||||
#include "systems/camera_system.hpp"
|
||||
@@ -59,7 +56,6 @@
|
||||
#include "systems/label_system.hpp"
|
||||
#include "systems/layout_system.hpp"
|
||||
#include "systems/render_system.hpp"
|
||||
#include "systems/spine_system.hpp"
|
||||
#include "systems/touch_system.hpp"
|
||||
#include "systems/world_system.hpp"
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace e2d
|
||||
class shader_asset;
|
||||
class shape_asset;
|
||||
class sound_asset;
|
||||
class spine_asset;
|
||||
class sprite_asset;
|
||||
class text_asset;
|
||||
class texture_asset;
|
||||
@@ -57,7 +56,6 @@ namespace e2d
|
||||
class named;
|
||||
class renderer;
|
||||
class scene;
|
||||
class spine_player;
|
||||
class sprite_renderer;
|
||||
class touchable;
|
||||
class widget;
|
||||
@@ -66,7 +64,6 @@ namespace e2d
|
||||
class flipbook;
|
||||
class model;
|
||||
class prefab;
|
||||
class spine;
|
||||
class sprite;
|
||||
|
||||
class camera_system;
|
||||
@@ -76,7 +73,6 @@ namespace e2d
|
||||
class label_system;
|
||||
class layout_system;
|
||||
class render_system;
|
||||
class spine_system;
|
||||
class touch_system;
|
||||
class world_system;
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../_high.hpp"
|
||||
|
||||
#include "../library.hpp"
|
||||
#include "../resources/spine.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class spine_asset final : public content_asset<spine_asset, spine> {
|
||||
public:
|
||||
static const char* type_name() noexcept { return "spine_asset"; }
|
||||
static load_async_result load_async(const library& library, str_view address);
|
||||
};
|
||||
}
|
||||
@@ -1,376 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "_components.hpp"
|
||||
|
||||
#include "../assets/spine_asset.hpp"
|
||||
#include "../assets/material_asset.hpp"
|
||||
|
||||
struct spSkeleton;
|
||||
struct spSkeletonClipping;
|
||||
struct spAnimationState;
|
||||
|
||||
namespace e2d::spine_player_events
|
||||
{
|
||||
class custom_evt;
|
||||
class end_evt;
|
||||
class complete_evt;
|
||||
|
||||
using event = std::variant<
|
||||
custom_evt,
|
||||
end_evt,
|
||||
complete_evt>;
|
||||
}
|
||||
|
||||
namespace e2d::spine_player_commands
|
||||
{
|
||||
class clear_track_cmd;
|
||||
class set_anim_cmd;
|
||||
class add_anim_cmd;
|
||||
class set_empty_anim_cmd;
|
||||
class add_empty_anim_cmd;
|
||||
|
||||
using command = std::variant<
|
||||
clear_track_cmd,
|
||||
set_anim_cmd,
|
||||
add_anim_cmd,
|
||||
set_empty_anim_cmd,
|
||||
add_empty_anim_cmd>;
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class bad_spine_player_access final : public exception {
|
||||
public:
|
||||
const char* what() const noexcept final {
|
||||
return "bad spine player access";
|
||||
}
|
||||
};
|
||||
|
||||
class spine_player final {
|
||||
public:
|
||||
using clipping_ptr = std::shared_ptr<spSkeletonClipping>;
|
||||
using skeleton_ptr = std::shared_ptr<spSkeleton>;
|
||||
using animation_ptr = std::shared_ptr<spAnimationState>;
|
||||
public:
|
||||
spine_player() = default;
|
||||
spine_player(const spine_asset::ptr& spine);
|
||||
|
||||
spine_player& spine(
|
||||
const spine_asset::ptr& value);
|
||||
|
||||
bool skin(str_view name);
|
||||
bool attachment(str_view slot, str_view name);
|
||||
|
||||
bool has_skin(str_view name) const noexcept;
|
||||
bool has_animation(str_view name) const noexcept;
|
||||
|
||||
const spine_asset::ptr& spine() const noexcept;
|
||||
const clipping_ptr& clipper() const noexcept;
|
||||
const skeleton_ptr& skeleton() const noexcept;
|
||||
const animation_ptr& animation() const noexcept;
|
||||
|
||||
spine_player& materials(flat_map<str_hash, material_asset::ptr> value) noexcept;
|
||||
const flat_map<str_hash, material_asset::ptr>& materials() const noexcept;
|
||||
material_asset::ptr find_material(str_hash name) const noexcept;
|
||||
private:
|
||||
spine_asset::ptr spine_;
|
||||
clipping_ptr clipping_;
|
||||
skeleton_ptr skeleton_;
|
||||
animation_ptr animation_;
|
||||
flat_map<str_hash, material_asset::ptr> materials_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
template <>
|
||||
class factory_loader<spine_player> final : factory_loader<> {
|
||||
public:
|
||||
static const char* schema_source;
|
||||
|
||||
bool operator()(
|
||||
spine_player& component,
|
||||
const fill_context& ctx) const;
|
||||
|
||||
bool operator()(
|
||||
asset_dependencies& dependencies,
|
||||
const collect_context& ctx) const;
|
||||
};
|
||||
|
||||
template <>
|
||||
class factory_loader<events<spine_player_events::event>> final : factory_loader<> {
|
||||
public:
|
||||
static const char* schema_source;
|
||||
|
||||
bool operator()(
|
||||
events<spine_player_events::event>& component,
|
||||
const fill_context& ctx) const;
|
||||
|
||||
bool operator()(
|
||||
asset_dependencies& dependencies,
|
||||
const collect_context& ctx) const;
|
||||
};
|
||||
|
||||
template <>
|
||||
class factory_loader<commands<spine_player_commands::command>> final : factory_loader<> {
|
||||
public:
|
||||
static const char* schema_source;
|
||||
|
||||
bool operator()(
|
||||
commands<spine_player_commands::command>& component,
|
||||
const fill_context& ctx) const;
|
||||
|
||||
bool operator()(
|
||||
asset_dependencies& dependencies,
|
||||
const collect_context& ctx) const;
|
||||
};
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
template <>
|
||||
class component_inspector<spine_player> final : component_inspector<> {
|
||||
public:
|
||||
static const char* title;
|
||||
|
||||
void operator()(gcomponent<spine_player>& c) const;
|
||||
};
|
||||
}
|
||||
|
||||
namespace e2d::spine_player_events
|
||||
{
|
||||
class custom_evt final {
|
||||
public:
|
||||
custom_evt() = default;
|
||||
|
||||
custom_evt(str name)
|
||||
: name_(std::move(name)) {}
|
||||
|
||||
custom_evt& name(str value) noexcept {
|
||||
name_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
custom_evt& int_value(i32 value) noexcept {
|
||||
int_value_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
custom_evt& float_value(f32 value) noexcept {
|
||||
float_value_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
custom_evt& string_value(str value) noexcept {
|
||||
string_value_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const str& name() const noexcept { return name_; }
|
||||
[[nodiscard]] i32 int_value() const noexcept { return int_value_; }
|
||||
[[nodiscard]] f32 float_value() const noexcept { return float_value_; }
|
||||
[[nodiscard]] const str& string_value() const noexcept { return string_value_; }
|
||||
private:
|
||||
str name_;
|
||||
i32 int_value_{0};
|
||||
f32 float_value_{0.f};
|
||||
str string_value_;
|
||||
};
|
||||
|
||||
class end_evt final {
|
||||
public:
|
||||
end_evt() = default;
|
||||
|
||||
end_evt(str message)
|
||||
: message_(std::move(message)) {}
|
||||
|
||||
end_evt& message(str value) noexcept {
|
||||
message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const str& message() const noexcept { return message_; }
|
||||
private:
|
||||
str message_;
|
||||
};
|
||||
|
||||
class complete_evt final {
|
||||
public:
|
||||
complete_evt() = default;
|
||||
|
||||
complete_evt(str message)
|
||||
: message_(std::move(message)) {}
|
||||
|
||||
complete_evt& message(str value) noexcept {
|
||||
message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const str& message() const noexcept { return message_; }
|
||||
private:
|
||||
str message_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace e2d::spine_player_commands
|
||||
{
|
||||
class clear_track_cmd final {
|
||||
public:
|
||||
clear_track_cmd(u32 track)
|
||||
: track_(track) {}
|
||||
|
||||
[[nodiscard]] u32 track() const noexcept { return track_; }
|
||||
private:
|
||||
u32 track_{0u};
|
||||
};
|
||||
|
||||
class set_anim_cmd final {
|
||||
public:
|
||||
set_anim_cmd(u32 track, str name)
|
||||
: track_(track)
|
||||
, name_(std::move(name)) {}
|
||||
|
||||
set_anim_cmd& loop(bool value) noexcept {
|
||||
loop_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
set_anim_cmd& end_message(str value) noexcept {
|
||||
end_message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
set_anim_cmd& complete_message(str value) noexcept {
|
||||
complete_message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 track() const noexcept { return track_; }
|
||||
[[nodiscard]] const str& name() const noexcept { return name_; }
|
||||
[[nodiscard]] bool loop() const noexcept { return loop_; }
|
||||
[[nodiscard]] const str& end_message() const noexcept { return complete_message_; }
|
||||
[[nodiscard]] const str& complete_message() const noexcept { return complete_message_; }
|
||||
private:
|
||||
u32 track_{0u};
|
||||
str name_;
|
||||
bool loop_{false};
|
||||
str end_message_;
|
||||
str complete_message_;
|
||||
};
|
||||
|
||||
class add_anim_cmd final {
|
||||
public:
|
||||
add_anim_cmd(u32 track, str name)
|
||||
: track_(track)
|
||||
, name_(std::move(name)) {}
|
||||
|
||||
add_anim_cmd& loop(bool value) noexcept {
|
||||
loop_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
add_anim_cmd& delay(f32 value) noexcept {
|
||||
delay_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
add_anim_cmd& end_message(str value) noexcept {
|
||||
end_message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
add_anim_cmd& complete_message(str value) noexcept {
|
||||
complete_message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 track() const noexcept { return track_; }
|
||||
[[nodiscard]] const str& name() const noexcept { return name_; }
|
||||
[[nodiscard]] bool loop() const noexcept { return loop_; }
|
||||
[[nodiscard]] f32 delay() const noexcept { return delay_; }
|
||||
[[nodiscard]] const str& end_message() const noexcept { return end_message_; }
|
||||
[[nodiscard]] const str& complete_message() const noexcept { return complete_message_; }
|
||||
private:
|
||||
u32 track_{0u};
|
||||
str name_;
|
||||
bool loop_{false};
|
||||
f32 delay_{0.f};
|
||||
str end_message_;
|
||||
str complete_message_;
|
||||
};
|
||||
|
||||
class set_empty_anim_cmd final {
|
||||
public:
|
||||
set_empty_anim_cmd(u32 track)
|
||||
: track_(track) {}
|
||||
|
||||
set_empty_anim_cmd& mix_duration(f32 value) noexcept {
|
||||
mix_duration_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
set_empty_anim_cmd& end_message(str value) noexcept {
|
||||
end_message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
set_empty_anim_cmd& complete_message(str value) noexcept {
|
||||
complete_message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 track() const noexcept { return track_; }
|
||||
[[nodiscard]] f32 mix_duration() const noexcept { return mix_duration_; }
|
||||
[[nodiscard]] const str& end_message() const noexcept { return end_message_; }
|
||||
[[nodiscard]] const str& complete_message() const noexcept { return complete_message_; }
|
||||
private:
|
||||
u32 track_{0u};
|
||||
f32 mix_duration_{0.f};
|
||||
str end_message_;
|
||||
str complete_message_;
|
||||
};
|
||||
|
||||
class add_empty_anim_cmd final {
|
||||
public:
|
||||
add_empty_anim_cmd(u32 track)
|
||||
: track_(track) {}
|
||||
|
||||
add_empty_anim_cmd& delay(f32 value) noexcept {
|
||||
delay_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
add_empty_anim_cmd& mix_duration(f32 value) noexcept {
|
||||
mix_duration_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
add_empty_anim_cmd& end_message(str value) noexcept {
|
||||
end_message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
add_empty_anim_cmd& complete_message(str value) noexcept {
|
||||
complete_message_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 track() const noexcept { return track_; }
|
||||
[[nodiscard]] f32 delay() const noexcept { return delay_; }
|
||||
[[nodiscard]] f32 mix_duration() const noexcept { return mix_duration_; }
|
||||
[[nodiscard]] const str& end_message() const noexcept { return end_message_; }
|
||||
[[nodiscard]] const str& complete_message() const noexcept { return complete_message_; }
|
||||
private:
|
||||
u32 track_{0u};
|
||||
f32 delay_{0.f};
|
||||
f32 mix_duration_{0.f};
|
||||
str end_message_;
|
||||
str complete_message_;
|
||||
};
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../_high.hpp"
|
||||
|
||||
struct spAtlas;
|
||||
struct spSkeletonData;
|
||||
struct spAnimationStateData;
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class bad_spine_access final : public exception {
|
||||
public:
|
||||
const char* what() const noexcept final {
|
||||
return "bad spine access";
|
||||
}
|
||||
};
|
||||
|
||||
class spine final {
|
||||
public:
|
||||
using atlas_ptr = std::shared_ptr<spAtlas>;
|
||||
using skeleton_data_ptr = std::shared_ptr<spSkeletonData>;
|
||||
using animation_data_ptr = std::shared_ptr<spAnimationStateData>;
|
||||
public:
|
||||
spine() = default;
|
||||
~spine() noexcept = default;
|
||||
|
||||
spine(spine&& other) noexcept;
|
||||
spine& operator=(spine&& other) noexcept;
|
||||
|
||||
spine(const spine& other);
|
||||
spine& operator=(const spine& other);
|
||||
|
||||
void clear() noexcept;
|
||||
void swap(spine& other) noexcept;
|
||||
|
||||
spine& assign(spine&& other) noexcept;
|
||||
spine& assign(const spine& other);
|
||||
|
||||
spine& set_atlas(atlas_ptr atlas);
|
||||
spine& set_skeleton(skeleton_data_ptr skeleton);
|
||||
|
||||
spine& set_default_mix(f32 duration);
|
||||
spine& set_animation_mix(
|
||||
const str& from,
|
||||
const str& to,
|
||||
f32 duration);
|
||||
|
||||
const atlas_ptr& atlas() const noexcept;
|
||||
const skeleton_data_ptr& skeleton() const noexcept;
|
||||
const animation_data_ptr& animation() const noexcept;
|
||||
private:
|
||||
atlas_ptr atlas_;
|
||||
skeleton_data_ptr skeleton_;
|
||||
animation_data_ptr animation_;
|
||||
};
|
||||
|
||||
void swap(spine& l, spine& r) noexcept;
|
||||
bool operator==(const spine& l, const spine& r) noexcept;
|
||||
bool operator!=(const spine& l, const spine& r) noexcept;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "_systems.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class spine_system final
|
||||
: public ecs::system<ecs::after<systems::update_event>> {
|
||||
public:
|
||||
spine_system();
|
||||
~spine_system() noexcept;
|
||||
|
||||
void process(
|
||||
ecs::registry& owner,
|
||||
const ecs::after<systems::update_event>& trigger) override;
|
||||
private:
|
||||
class internal_state;
|
||||
std::unique_ptr<internal_state> state_;
|
||||
};
|
||||
}
|
||||
Submodule modules/spine deleted from 9fabc60323
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"passes" : [{
|
||||
"shader" : "../shaders/spine_shader.json",
|
||||
"state_block" : {
|
||||
"blending_state" : {
|
||||
"src_factor" : "one",
|
||||
"dst_factor" : "one"
|
||||
},
|
||||
"capabilities_state" : {
|
||||
"blending" : true
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"passes" : [{
|
||||
"shader" : "../shaders/spine_shader.json",
|
||||
"state_block" : {
|
||||
"blending_state" : {
|
||||
"src_factor" : "dst_color",
|
||||
"dst_factor" : "one_minus_src_alpha"
|
||||
},
|
||||
"capabilities_state" : {
|
||||
"blending" : true
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"passes" : [{
|
||||
"shader" : "../shaders/spine_shader.json",
|
||||
"state_block" : {
|
||||
"blending_state" : {
|
||||
"src_factor" : "one",
|
||||
"dst_factor" : "one_minus_src_alpha"
|
||||
},
|
||||
"capabilities_state" : {
|
||||
"blending" : true
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"passes" : [{
|
||||
"shader" : "../shaders/spine_shader.json",
|
||||
"state_block" : {
|
||||
"blending_state" : {
|
||||
"src_factor" : "one",
|
||||
"dst_factor" : "one_minus_src_color"
|
||||
},
|
||||
"capabilities_state" : {
|
||||
"blending" : true
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"prefab" : "spine_prefab.json",
|
||||
"components" : {
|
||||
"named" : {
|
||||
"name" : "coin"
|
||||
},
|
||||
"spine_player" : {
|
||||
"spine" : "../spines/coin_spine.json"
|
||||
},
|
||||
"spine_player.commands" : {
|
||||
"commands" : [{
|
||||
"type" : "set_anim_cmd",
|
||||
"desc" : {
|
||||
"track" : 0,
|
||||
"name" : "animation",
|
||||
"loop" : true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"prefab" : "spine_prefab.json",
|
||||
"components" : {
|
||||
"named" : {
|
||||
"name" : "dragon"
|
||||
},
|
||||
"spine_player" : {
|
||||
"spine" : "../spines/dragon_spine.json"
|
||||
},
|
||||
"spine_player.commands" : {
|
||||
"commands" : [{
|
||||
"type" : "set_anim_cmd",
|
||||
"desc" : {
|
||||
"track" : 0,
|
||||
"name" : "flying",
|
||||
"loop" : true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"prefab" : "spine_prefab.json",
|
||||
"components" : {
|
||||
"named" : {
|
||||
"name" : "raptor"
|
||||
},
|
||||
"spine_player" : {
|
||||
"spine" : "../spines/raptor_spine.json"
|
||||
},
|
||||
"spine_player.commands" : {
|
||||
"commands" : [{
|
||||
"type" : "add_anim_cmd",
|
||||
"desc" : {
|
||||
"track" : 0,
|
||||
"name" : "walk"
|
||||
}
|
||||
}, {
|
||||
"type" : "add_anim_cmd",
|
||||
"desc" : {
|
||||
"track" : 0,
|
||||
"name" : "roar"
|
||||
}
|
||||
}, {
|
||||
"type" : "add_anim_cmd",
|
||||
"desc" : {
|
||||
"track" : 0,
|
||||
"name" : "walk",
|
||||
"loop" : true
|
||||
}
|
||||
}, {
|
||||
"type" : "add_anim_cmd",
|
||||
"desc" : {
|
||||
"track" : 1,
|
||||
"name" : "gun-grab",
|
||||
"delay" : 2
|
||||
}
|
||||
}, {
|
||||
"type" : "add_anim_cmd",
|
||||
"desc" : {
|
||||
"track" : 1,
|
||||
"name" : "gun-holster",
|
||||
"delay" : 3
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"components" : {
|
||||
"named" : {
|
||||
"name" : "spine"
|
||||
},
|
||||
"renderer" : {},
|
||||
"spine_player" : {
|
||||
"materials" : {
|
||||
"additive" : "../materials/spine_material_additive.json",
|
||||
"multiply" : "../materials/spine_material_multiply.json",
|
||||
"normal" : "../materials/spine_material_normal.json",
|
||||
"screen" : "../materials/spine_material_screen.json"
|
||||
}
|
||||
},
|
||||
"spine_player.events" : {},
|
||||
"spine_player.commands" : {}
|
||||
}
|
||||
}
|
||||
@@ -2,38 +2,5 @@
|
||||
"prefab" : "../prefabs/scene_prefab.json",
|
||||
"children" : [{
|
||||
"prefab" : "../prefabs/camera_prefab.json"
|
||||
},{
|
||||
"prefab" : "../prefabs/coin_prefab.json",
|
||||
"components" : {
|
||||
"actor" : {
|
||||
"translation" : [350,250],
|
||||
"scale" : 0.25
|
||||
},
|
||||
"named" : {
|
||||
"name" : "coin"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"prefab" : "../prefabs/raptor_prefab.json",
|
||||
"components" : {
|
||||
"actor" : {
|
||||
"translation" : [300,-350],
|
||||
"scale" : 0.25
|
||||
},
|
||||
"named" : {
|
||||
"name" : "raptor"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"prefab" : "../prefabs/dragon_prefab.json",
|
||||
"components" : {
|
||||
"actor" : {
|
||||
"translation" : [-100,0],
|
||||
"scale" : 0.9
|
||||
},
|
||||
"named" : {
|
||||
"name" : "dragon"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
varying vec2 v_st0;
|
||||
varying vec4 v_color0;
|
||||
|
||||
void main() {
|
||||
vec4 c = texture2D(u_texture, v_st0) * v_color0;
|
||||
c.rgb *= c.a;
|
||||
gl_FragColor = c;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"vertex" : "spine_shader.vert",
|
||||
"fragment" : "spine_shader.frag"
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
uniform vec2 u_screen_s;
|
||||
uniform mat4 u_matrix_vp;
|
||||
|
||||
attribute vec3 a_vertex;
|
||||
attribute vec2 a_st0;
|
||||
attribute vec4 a_color0;
|
||||
|
||||
varying vec2 v_st0;
|
||||
varying vec4 v_color0;
|
||||
|
||||
vec2 round(vec2 v) {
|
||||
return vec2(
|
||||
floor(v.x + 0.5),
|
||||
floor(v.y + 0.5));
|
||||
}
|
||||
|
||||
vec4 pixel_snap(vec4 pos) {
|
||||
vec2 hpc = u_screen_s * 0.5;
|
||||
vec2 pixel_pos = round((pos.xy / pos.w) * hpc);
|
||||
pos.xy = pixel_pos / hpc * pos.w;
|
||||
return pos;
|
||||
}
|
||||
|
||||
vec4 vertex_to_homo(vec3 pos) {
|
||||
return vec4(pos, 1.0) * u_matrix_vp;
|
||||
}
|
||||
|
||||
void main() {
|
||||
v_st0 = a_st0;
|
||||
v_color0 = a_color0;
|
||||
#ifndef VERTEX_SNAPPING_ON
|
||||
gl_Position = vertex_to_homo(a_vertex);
|
||||
#else
|
||||
gl_Position = pixel_snap(vertex_to_homo(a_vertex));
|
||||
#endif
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:772bf78b10c22079c0afb46edfff2eff789c4082cd52f4124868a04905b72bbf
|
||||
size 2657
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:833bc92c2a02695c326080b72f8636206ec53f361010a6b02324565b470f690b
|
||||
size 831
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:21bc65e3de306d698df5c6a6519786a430d8529bc58f01f87013c9927819f87a
|
||||
size 402363
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"atlas" : "coin/coin.atlas",
|
||||
"skeleton" : "coin/coin-pro.skel",
|
||||
"skeleton_scale" : 1.0
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2d299087ede92db92396af117f151e8f50abecb57094f34b031d0a389a53d1ad
|
||||
size 7073
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fa3a79e67d926b1e5f017ecd2f2bc2f73fa02a766f27cc83a6547f0c90556c58
|
||||
size 4224
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a45ac203747ffc4802c83860b20bcb380b405ea55734992defb5fb64f49bbfa0
|
||||
size 628537
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:86b1a3fcd15a538e08535f0fad4b6cc1c9595060aae0d558c0f2bcc1d09a2833
|
||||
size 194829
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"atlas" : "dragon/dragon.atlas",
|
||||
"skeleton" : "dragon/dragon-ess.skel",
|
||||
"skeleton_scale" : 1.0
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c8d0e5057c92306900f39879e51642500b841825cedb47833bbfa129978b5757
|
||||
size 172896
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:83c00999f00c4ac395ba063291d02131fb2a8869cb6d8f4fd20bc15131d52d54
|
||||
size 63077
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dd001b421b535adb21c74148790d8b576d17aedaeecf0f2ac6318619b94a932b
|
||||
size 4210
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:879d84230024a1529ea994e7cd6416c5883f4b74b0d268b5e2dea1cbe2d00777
|
||||
size 480392
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"atlas": "raptor/raptor.atlas",
|
||||
"skeleton": "raptor/raptor-pro.json-large",
|
||||
"skeleton_scale": 1.0,
|
||||
"default_animation_mix" : 0.5,
|
||||
"animation_mixes": [
|
||||
{
|
||||
"from": "walk",
|
||||
"to": "roar",
|
||||
"duration": 0.5
|
||||
},
|
||||
{
|
||||
"from": "roar",
|
||||
"to": "walk",
|
||||
"duration": 0.5
|
||||
},
|
||||
{
|
||||
"from": "walk",
|
||||
"to": "jump",
|
||||
"duration": 0.5
|
||||
},
|
||||
{
|
||||
"from": "jump",
|
||||
"to": "walk",
|
||||
"duration": 0.5
|
||||
},
|
||||
{
|
||||
"from": "roar",
|
||||
"to": "jump",
|
||||
"duration": 0.5
|
||||
},
|
||||
{
|
||||
"from": "jump",
|
||||
"to": "roar",
|
||||
"duration": 0.5
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -29,44 +29,6 @@ namespace
|
||||
if ( k.is_key_pressed(keyboard_key::lsuper) && k.is_key_just_released(keyboard_key::enter) ) {
|
||||
the<window>().toggle_fullscreen(!the<window>().fullscreen());
|
||||
}
|
||||
|
||||
// use keys R, J, G to start animations
|
||||
const bool roar = k.is_key_just_pressed(keyboard_key::r);
|
||||
const bool jump = k.is_key_just_pressed(keyboard_key::j);
|
||||
const bool gun_grab = k.is_key_just_pressed(keyboard_key::g);
|
||||
|
||||
if ( roar || jump || gun_grab ) {
|
||||
owner.for_each_component<spine_player>([
|
||||
roar, jump, gun_grab
|
||||
](ecs::entity e, const spine_player& p) {
|
||||
if ( roar && p.has_animation("roar") ) {
|
||||
e.ensure_component<commands<spine_player_commands::command>>()
|
||||
.add(spine_player_commands::set_anim_cmd(0, "roar")
|
||||
.complete_message("to_walk"));
|
||||
} else if ( jump && p.has_animation("jump") ) {
|
||||
e.ensure_component<commands<spine_player_commands::command>>()
|
||||
.add(spine_player_commands::set_anim_cmd(0, "jump")
|
||||
.complete_message("to_walk"));
|
||||
} else if ( gun_grab && p.has_animation("gun-grab") ) {
|
||||
e.ensure_component<commands<spine_player_commands::command>>()
|
||||
.add(spine_player_commands::set_anim_cmd(1, "gun-grab"))
|
||||
.add(spine_player_commands::add_anim_cmd(1, "gun-holster").delay(3.f));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
owner.for_joined_components<events<spine_player_events::event>>([
|
||||
](ecs::entity e, const events<spine_player_events::event>& pe) {
|
||||
for ( const auto& evt : pe.get() ) {
|
||||
if ( auto complete = std::get_if<spine_player_events::complete_evt>(&evt);
|
||||
complete && complete->message() == "to_walk" )
|
||||
{
|
||||
e.ensure_component<commands<spine_player_commands::command>>()
|
||||
.add(spine_player_commands::add_anim_cmd(0, "walk")
|
||||
.loop(true));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,415 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <enduro2d/high/assets/spine_asset.hpp>
|
||||
|
||||
#include <enduro2d/high/assets/json_asset.hpp>
|
||||
#include <enduro2d/high/assets/binary_asset.hpp>
|
||||
#include <enduro2d/high/assets/texture_asset.hpp>
|
||||
|
||||
#include <spine/spine.h>
|
||||
#include <spine/extension.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
|
||||
class spine_asset_loading_exception final : public asset_loading_exception {
|
||||
const char* what() const noexcept final {
|
||||
return "spine asset loading exception";
|
||||
}
|
||||
};
|
||||
|
||||
const char* spine_asset_schema_source = R"json({
|
||||
"type" : "object",
|
||||
"required" : [ "atlas", "skeleton" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"atlas" : { "$ref" : "#/common_definitions/address" },
|
||||
"skeleton" : { "$ref" : "#/common_definitions/address" },
|
||||
"skeleton_scale" : { "type" : "number" },
|
||||
"default_animation_mix" : { "type" : "number" },
|
||||
"animation_mixes" : { "$ref": "#/definitions/animation_mixes" }
|
||||
},
|
||||
"definitions" : {
|
||||
"animation_mixes" : {
|
||||
"type" : "array",
|
||||
"items" : { "$ref": "#/definitions/animation_mix" }
|
||||
},
|
||||
"animation_mix" : {
|
||||
"type" : "object",
|
||||
"required" : [ "from", "to", "duration" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"from" : { "$ref": "#/common_definitions/name" },
|
||||
"to" : { "$ref": "#/common_definitions/name" },
|
||||
"duration" : { "type" : "number" }
|
||||
}
|
||||
}
|
||||
}
|
||||
})json";
|
||||
|
||||
const rapidjson::SchemaDocument& spine_asset_schema() {
|
||||
static std::mutex mutex;
|
||||
static std::unique_ptr<rapidjson::SchemaDocument> schema;
|
||||
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
if ( !schema ) {
|
||||
rapidjson::Document doc;
|
||||
if ( doc.Parse(spine_asset_schema_source).HasParseError() ) {
|
||||
the<debug>().error("ASSETS: Failed to parse spine asset schema");
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
json_utils::add_common_schema_definitions(doc);
|
||||
schema = std::make_unique<rapidjson::SchemaDocument>(doc);
|
||||
}
|
||||
|
||||
return *schema;
|
||||
}
|
||||
|
||||
struct animation_mix {
|
||||
str from;
|
||||
str to;
|
||||
f32 duration{0.f};
|
||||
};
|
||||
|
||||
animation_mix parse_animation_mix(const rapidjson::Value& root) {
|
||||
animation_mix mix;
|
||||
|
||||
E2D_ASSERT(root.HasMember("from") && root["from"].IsString());
|
||||
if ( !json_utils::try_parse_value(root["from"], mix.from) ) {
|
||||
the<debug>().error("SPINE: Incorrect formating of 'from' property");
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
E2D_ASSERT(root.HasMember("to") && root["to"].IsString());
|
||||
if ( !json_utils::try_parse_value(root["to"], mix.to) ) {
|
||||
the<debug>().error("SPINE: Incorrect formating of 'to' property");
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
E2D_ASSERT(root.HasMember("duration") && root["duration"].IsNumber());
|
||||
if ( !json_utils::try_parse_value(root["duration"], mix.duration) ) {
|
||||
the<debug>().error("SPINE: Incorrect formating of 'duration' property");
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
return mix;
|
||||
}
|
||||
|
||||
struct atlas_internal_state {
|
||||
asset_group loaded;
|
||||
asset_dependencies loading;
|
||||
};
|
||||
|
||||
stdex::promise<spine::atlas_ptr> load_atlas(
|
||||
const library& library,
|
||||
const str& parent_address,
|
||||
const str& atlas_address)
|
||||
{
|
||||
const str atlas_path = path::combine(parent_address, atlas_address);
|
||||
const str atlas_folder = path::parent_path(atlas_path);
|
||||
|
||||
return library.load_asset_async<binary_asset>(atlas_path)
|
||||
.then([
|
||||
&library,
|
||||
atlas_path,
|
||||
atlas_folder
|
||||
](const binary_asset::load_result& atlas_data){
|
||||
return the<deferrer>().do_in_worker_thread([](){})
|
||||
.then([
|
||||
&library,
|
||||
atlas_data,
|
||||
atlas_path,
|
||||
atlas_folder
|
||||
](){
|
||||
auto atlas_internal = std::make_unique<atlas_internal_state>();
|
||||
|
||||
spine::atlas_ptr atlas(
|
||||
spAtlas_create(
|
||||
reinterpret_cast<const char*>(atlas_data->content().data()),
|
||||
math::numeric_cast<int>(atlas_data->content().size()),
|
||||
atlas_folder.c_str(),
|
||||
atlas_internal.get()),
|
||||
spAtlas_dispose);
|
||||
|
||||
if ( !atlas ) {
|
||||
the<debug>().error("SPINE: Failed to create preload atlas");
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
return atlas_internal->loading.load_async(library);
|
||||
})
|
||||
.then([
|
||||
atlas_data,
|
||||
atlas_path,
|
||||
atlas_folder
|
||||
](auto&& dependencies){
|
||||
auto atlas_internal = std::make_unique<atlas_internal_state>();
|
||||
atlas_internal->loaded = std::forward<decltype(dependencies)>(dependencies);
|
||||
|
||||
spine::atlas_ptr atlas(
|
||||
spAtlas_create(
|
||||
reinterpret_cast<const char*>(atlas_data->content().data()),
|
||||
math::numeric_cast<int>(atlas_data->content().size()),
|
||||
atlas_folder.c_str(),
|
||||
atlas_internal.get()),
|
||||
spAtlas_dispose);
|
||||
|
||||
if ( !atlas ) {
|
||||
the<debug>().error("SPINE: Failed to create preloaded atlas");
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
for ( const spAtlasPage* page = atlas->pages; page; page = page->next ) {
|
||||
if ( !page->rendererObject ) {
|
||||
the<debug>().error("SPINE: Failed to create preloaded atlas");
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
}
|
||||
|
||||
atlas->rendererObject = nullptr;
|
||||
return atlas;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
stdex::promise<spine::skeleton_data_ptr> load_skeleton_data(
|
||||
const library& library,
|
||||
const str& parent_address,
|
||||
const str& skeleton_address,
|
||||
f32 skeleton_scale,
|
||||
const spine::atlas_ptr& atlas)
|
||||
{
|
||||
str address = path::combine(parent_address, skeleton_address);
|
||||
return library.load_asset_async<binary_asset>(address)
|
||||
.then([
|
||||
atlas,
|
||||
skeleton_scale,
|
||||
address = std::move(address)
|
||||
](const binary_asset::load_result& skeleton_data){
|
||||
return the<deferrer>().do_in_worker_thread([
|
||||
atlas,
|
||||
skeleton_scale,
|
||||
address = std::move(address),
|
||||
skeleton_data
|
||||
](){
|
||||
if ( strings::ends_with(address, ".skel") ) {
|
||||
using skeleton_bin_ptr = std::unique_ptr<
|
||||
spSkeletonBinary,
|
||||
decltype(&::spSkeletonBinary_dispose)>;
|
||||
|
||||
skeleton_bin_ptr binary_skeleton(
|
||||
spSkeletonBinary_create(atlas.get()),
|
||||
spSkeletonBinary_dispose);
|
||||
|
||||
if ( !binary_skeleton ) {
|
||||
the<debug>().error("SPINE: Failed to create binary skeleton");
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
binary_skeleton->scale = skeleton_scale;
|
||||
|
||||
spine::skeleton_data_ptr data_skeleton(
|
||||
spSkeletonBinary_readSkeletonData(
|
||||
binary_skeleton.get(),
|
||||
reinterpret_cast<const unsigned char*>(skeleton_data->content().data()),
|
||||
math::numeric_cast<int>(skeleton_data->content().size())),
|
||||
spSkeletonData_dispose);
|
||||
|
||||
if ( !data_skeleton ) {
|
||||
the<debug>().error("SPINE: Failed to read binary skeleton data:\n"
|
||||
"--> Error: %0",
|
||||
binary_skeleton->error);
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
return data_skeleton;
|
||||
} else {
|
||||
using skeleton_json_ptr = std::unique_ptr<
|
||||
spSkeletonJson,
|
||||
decltype(&::spSkeletonJson_dispose)>;
|
||||
|
||||
skeleton_json_ptr json_skeleton(
|
||||
spSkeletonJson_create(atlas.get()),
|
||||
spSkeletonJson_dispose);
|
||||
|
||||
if ( !json_skeleton ) {
|
||||
the<debug>().error("SPINE: Failed to create json skeleton");
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
json_skeleton->scale = skeleton_scale;
|
||||
|
||||
spine::skeleton_data_ptr data_skeleton(
|
||||
spSkeletonJson_readSkeletonData(
|
||||
json_skeleton.get(),
|
||||
reinterpret_cast<const char*>(skeleton_data->content().data())),
|
||||
spSkeletonData_dispose);
|
||||
|
||||
if ( !data_skeleton ) {
|
||||
the<debug>().error("SPINE: Failed to read json skeleton data:\n"
|
||||
"--> Error: %0",
|
||||
json_skeleton->error);
|
||||
throw spine_asset_loading_exception();
|
||||
}
|
||||
|
||||
return data_skeleton;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
stdex::promise<spine> parse_spine(
|
||||
const library& library,
|
||||
const str& parent_address,
|
||||
const rapidjson::Value& root)
|
||||
{
|
||||
f32 skeleton_scale{1.0f};
|
||||
if ( root.HasMember("skeleton_scale") ) {
|
||||
if ( !json_utils::try_parse_value(root["skeleton_scale"], skeleton_scale) ) {
|
||||
the<debug>().error("SPINE: Incorrect formating of 'skeleton_scale' property");
|
||||
}
|
||||
}
|
||||
|
||||
f32 default_animation_mix{0.5f};
|
||||
if ( root.HasMember("default_animation_mix") ) {
|
||||
if ( !json_utils::try_parse_value(root["default_animation_mix"], default_animation_mix) ) {
|
||||
the<debug>().error("SPINE: Incorrect formating of 'default_animation_mix' property");
|
||||
}
|
||||
}
|
||||
|
||||
vector<animation_mix> animation_mixes;
|
||||
if ( root.HasMember("animation_mixes") ) {
|
||||
E2D_ASSERT(root["animation_mixes"].IsArray());
|
||||
const auto& mixes_json = root["animation_mixes"];
|
||||
animation_mixes.reserve(mixes_json.Size());
|
||||
for ( rapidjson::SizeType i = 0; i < mixes_json.Size(); ++i ) {
|
||||
E2D_ASSERT(mixes_json[i].IsObject());
|
||||
animation_mixes.push_back(
|
||||
parse_animation_mix(mixes_json[i]));
|
||||
}
|
||||
}
|
||||
|
||||
E2D_ASSERT(root.HasMember("atlas") && root["atlas"].IsString());
|
||||
const str atlas_address = root["atlas"].GetString();
|
||||
|
||||
E2D_ASSERT(root.HasMember("skeleton") && root["skeleton"].IsString());
|
||||
const str skeleton_address = root["skeleton"].GetString();
|
||||
|
||||
return load_atlas(
|
||||
library,
|
||||
parent_address,
|
||||
atlas_address)
|
||||
.then([
|
||||
&library,
|
||||
parent_address,
|
||||
atlas_address,
|
||||
skeleton_scale,
|
||||
skeleton_address
|
||||
](const spine::atlas_ptr& atlas){
|
||||
return stdex::make_tuple_promise(std::make_tuple(
|
||||
stdex::make_resolved_promise(atlas),
|
||||
load_skeleton_data(
|
||||
library,
|
||||
parent_address,
|
||||
skeleton_address,
|
||||
skeleton_scale,
|
||||
atlas)));
|
||||
})
|
||||
.then([
|
||||
default_animation_mix,
|
||||
animation_mixes = std::move(animation_mixes)
|
||||
](const std::tuple<
|
||||
spine::atlas_ptr,
|
||||
spine::skeleton_data_ptr
|
||||
>& results){
|
||||
spine content;
|
||||
content.set_atlas(std::get<0>(results));
|
||||
content.set_skeleton(std::get<1>(results));
|
||||
content.set_default_mix(default_animation_mix);
|
||||
for ( const animation_mix& mix : animation_mixes ) {
|
||||
content.set_animation_mix(mix.from, mix.to, mix.duration);
|
||||
}
|
||||
return content;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
spine_asset::load_async_result spine_asset::load_async(
|
||||
const library& library, str_view address)
|
||||
{
|
||||
return library.load_asset_async<json_asset>(address)
|
||||
.then([
|
||||
&library,
|
||||
address = str(address),
|
||||
parent_address = path::parent_path(address)
|
||||
](const json_asset::load_result& spine_data){
|
||||
return the<deferrer>().do_in_worker_thread([address, spine_data](){
|
||||
const rapidjson::Document& doc = *spine_data->content();
|
||||
rapidjson::SchemaValidator validator(spine_asset_schema());
|
||||
|
||||
if ( doc.Accept(validator) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
rapidjson::StringBuffer sb;
|
||||
if ( validator.GetInvalidDocumentPointer().StringifyUriFragment(sb) ) {
|
||||
the<debug>().error("ASSET: Failed to validate asset json:\n"
|
||||
"--> Address: %0\n"
|
||||
"--> Invalid schema keyword: %1\n"
|
||||
"--> Invalid document pointer: %2",
|
||||
address,
|
||||
validator.GetInvalidSchemaKeyword(),
|
||||
sb.GetString());
|
||||
} else {
|
||||
the<debug>().error("ASSET: Failed to validate asset json");
|
||||
}
|
||||
|
||||
throw spine_asset_loading_exception();
|
||||
})
|
||||
.then([&library, parent_address, spine_data](){
|
||||
return parse_spine(
|
||||
library, parent_address, *spine_data->content());
|
||||
})
|
||||
.then([](auto&& content){
|
||||
return spine_asset::create(
|
||||
std::forward<decltype(content)>(content));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void _spAtlasPage_createTexture(spAtlasPage* self, const char* path) {
|
||||
try {
|
||||
E2D_ASSERT(self->atlas->rendererObject);
|
||||
atlas_internal_state& atlas_internal =
|
||||
*static_cast<atlas_internal_state*>(self->atlas->rendererObject);
|
||||
auto texture_res = atlas_internal.loaded.find_asset<texture_asset>(path);
|
||||
if ( texture_res ) {
|
||||
self->width = math::numeric_cast<int>(texture_res->content()->size().x);
|
||||
self->height = math::numeric_cast<int>(texture_res->content()->size().y);
|
||||
self->rendererObject = texture_res.release();
|
||||
} else {
|
||||
atlas_internal.loading.add_dependency<texture_asset>(path);
|
||||
}
|
||||
} catch(...) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void _spAtlasPage_disposeTexture(spAtlasPage* self) {
|
||||
E2D_UNUSED(texture_asset::load_result(
|
||||
static_cast<texture_asset*>(self->rendererObject), false));
|
||||
}
|
||||
|
||||
extern "C" char* _spUtil_readFile(const char* path, int* length) {
|
||||
E2D_ASSERT_MSG(false, "unimplemented by design");
|
||||
E2D_UNUSED(path, length);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1,922 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <enduro2d/high/components/spine_player.hpp>
|
||||
|
||||
#include <enduro2d/high/components/commands.hpp>
|
||||
#include <enduro2d/high/components/events.hpp>
|
||||
|
||||
#include <spine/spine.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
|
||||
std::optional<spine_player_events::custom_evt> parse_custom_evt(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
spine_player_events::custom_evt evt;
|
||||
|
||||
if ( root.HasMember("name") ) {
|
||||
str evt_name = evt.name();
|
||||
if ( !json_utils::try_parse_value(root["name"], evt_name) ) {
|
||||
the<debug>().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'custom_evt.name' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
evt.name(std::move(evt_name));
|
||||
}
|
||||
|
||||
if ( root.HasMember("int_value") ) {
|
||||
i32 evt_int_value = evt.int_value();
|
||||
if ( !json_utils::try_parse_value(root["int_value"], evt_int_value) ) {
|
||||
the<debug>().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'custom_evt.int_value' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
evt.int_value(evt_int_value);
|
||||
}
|
||||
|
||||
if ( root.HasMember("float_value") ) {
|
||||
f32 evt_float_value = evt.float_value();
|
||||
if ( !json_utils::try_parse_value(root["float_value"], evt_float_value) ) {
|
||||
the<debug>().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'custom_evt.float_value' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
evt.float_value(evt_float_value);
|
||||
}
|
||||
|
||||
if ( root.HasMember("string_value") ) {
|
||||
str evt_string_value = evt.string_value();
|
||||
if ( !json_utils::try_parse_value(root["string_value"], evt_string_value) ) {
|
||||
the<debug>().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'custom_evt.string_value' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
evt.string_value(std::move(evt_string_value));
|
||||
}
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
std::optional<spine_player_events::end_evt> parse_end_evt(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
spine_player_events::end_evt evt;
|
||||
|
||||
if ( root.HasMember("message") ) {
|
||||
str evt_message = evt.message();
|
||||
if ( !json_utils::try_parse_value(root["message"], evt_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'end_evt.message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
evt.message(std::move(evt_message));
|
||||
}
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
std::optional<spine_player_events::complete_evt> parse_complete_evt(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
spine_player_events::complete_evt evt;
|
||||
|
||||
if ( root.HasMember("message") ) {
|
||||
str evt_message = evt.message();
|
||||
if ( !json_utils::try_parse_value(root["message"], evt_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'complete_evt.message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
evt.message(std::move(evt_message));
|
||||
}
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
std::optional<spine_player_events::event> parse_event(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
str_hash command_type;
|
||||
E2D_ASSERT(root.HasMember("type") && root["type"].IsString());
|
||||
if ( !json_utils::try_parse_value(root["type"], command_type) ) {
|
||||
the<debug>().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'event.type' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
E2D_ASSERT(root.HasMember("desc") && root["desc"].IsObject());
|
||||
const auto& event_desc = root["desc"];
|
||||
|
||||
if ( command_type == make_hash("custom_evt") ) {
|
||||
auto evt = parse_custom_evt(event_desc);
|
||||
return evt ? evt : std::nullopt;
|
||||
} else if ( command_type == make_hash("end_evt") ) {
|
||||
auto evt = parse_end_evt(event_desc);
|
||||
return evt ? evt : std::nullopt;
|
||||
} else if ( command_type == make_hash("complete_evt") ) {
|
||||
auto evt = parse_complete_evt(event_desc);
|
||||
return evt ? evt : std::nullopt;
|
||||
} else {
|
||||
the<debug>().error("SPINE_PLAYER_EVENTS: Incorrect formatting of 'event.type' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<vector<spine_player_events::event>> parse_events(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsArray());
|
||||
|
||||
vector<spine_player_events::event> evts;
|
||||
evts.reserve(root.Size());
|
||||
|
||||
for ( rapidjson::SizeType i = 0; i < root.Size(); ++i ) {
|
||||
auto evt = parse_event(root[i]);
|
||||
if ( !evt ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
evts.push_back(std::move(*evt));
|
||||
}
|
||||
|
||||
return evts;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
|
||||
std::optional<spine_player_commands::clear_track_cmd> parse_clear_track_cmd(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
u32 cmd_track{0u};
|
||||
if ( !json_utils::try_parse_value(root["track"], cmd_track) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'clear_track_cmd.track' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return spine_player_commands::clear_track_cmd(cmd_track);
|
||||
}
|
||||
|
||||
std::optional<spine_player_commands::set_anim_cmd> parse_set_anim_cmd(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
u32 cmd_track{0u};
|
||||
E2D_ASSERT(root.HasMember("track"));
|
||||
if ( !json_utils::try_parse_value(root["track"], cmd_track) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.track' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
str cmd_name;
|
||||
E2D_ASSERT(root.HasMember("name"));
|
||||
if ( !json_utils::try_parse_value(root["name"], cmd_name) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.name' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
spine_player_commands::set_anim_cmd cmd(cmd_track, std::move(cmd_name));
|
||||
|
||||
if ( root.HasMember("loop") ) {
|
||||
bool cmd_loop = cmd.loop();
|
||||
if ( !json_utils::try_parse_value(root["loop"], cmd_loop) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.loop' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.loop(cmd_loop);
|
||||
}
|
||||
|
||||
if ( root.HasMember("end_message") ) {
|
||||
str cmd_end_message = cmd.end_message();
|
||||
if ( !json_utils::try_parse_value(root["end_message"], cmd_end_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.end_message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.end_message(std::move(cmd_end_message));
|
||||
}
|
||||
|
||||
if ( root.HasMember("complete_message") ) {
|
||||
str cmd_complete_message = cmd.complete_message();
|
||||
if ( !json_utils::try_parse_value(root["complete_message"], cmd_complete_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_anim_cmd.complete_message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.complete_message(std::move(cmd_complete_message));
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
std::optional<spine_player_commands::add_anim_cmd> parse_add_anim_cmd(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
u32 cmd_track{0u};
|
||||
E2D_ASSERT(root.HasMember("track"));
|
||||
if ( !json_utils::try_parse_value(root["track"], cmd_track) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.track' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
str cmd_name;
|
||||
E2D_ASSERT(root.HasMember("name"));
|
||||
if ( !json_utils::try_parse_value(root["name"], cmd_name) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.name' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
spine_player_commands::add_anim_cmd cmd(cmd_track, std::move(cmd_name));
|
||||
|
||||
if ( root.HasMember("loop") ) {
|
||||
bool cmd_loop = cmd.loop();
|
||||
if ( !json_utils::try_parse_value(root["loop"], cmd_loop) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.loop' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.loop(cmd_loop);
|
||||
}
|
||||
|
||||
if ( root.HasMember("delay") ) {
|
||||
f32 cmd_delay = cmd.delay();
|
||||
if ( !json_utils::try_parse_value(root["delay"], cmd_delay) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.delay' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.delay(cmd_delay);
|
||||
}
|
||||
|
||||
if ( root.HasMember("end_message") ) {
|
||||
str cmd_end_message = cmd.end_message();
|
||||
if ( !json_utils::try_parse_value(root["end_message"], cmd_end_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.end_message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.end_message(std::move(cmd_end_message));
|
||||
}
|
||||
|
||||
if ( root.HasMember("complete_message") ) {
|
||||
str cmd_complete_message = cmd.complete_message();
|
||||
if ( !json_utils::try_parse_value(root["complete_message"], cmd_complete_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_anim_cmd.complete_message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.complete_message(std::move(cmd_complete_message));
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
std::optional<spine_player_commands::set_empty_anim_cmd> parse_set_empty_anim_cmd(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
u32 cmd_track{0u};
|
||||
E2D_ASSERT(root.HasMember("track"));
|
||||
if ( !json_utils::try_parse_value(root["track"], cmd_track) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_empty_anim_cmd.track' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
spine_player_commands::set_empty_anim_cmd cmd(cmd_track);
|
||||
|
||||
if ( root.HasMember("mix_duration") ) {
|
||||
f32 cmd_mix_duration = cmd.mix_duration();
|
||||
if ( !json_utils::try_parse_value(root["mix_duration"], cmd_mix_duration) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_empty_anim_cmd.mix_duration' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.mix_duration(cmd_mix_duration);
|
||||
}
|
||||
|
||||
if ( root.HasMember("end_message") ) {
|
||||
str cmd_end_message = cmd.end_message();
|
||||
if ( !json_utils::try_parse_value(root["end_message"], cmd_end_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_empty_anim_cmd.end_message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.end_message(std::move(cmd_end_message));
|
||||
}
|
||||
|
||||
if ( root.HasMember("complete_message") ) {
|
||||
str cmd_complete_message = cmd.complete_message();
|
||||
if ( !json_utils::try_parse_value(root["complete_message"], cmd_complete_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'set_empty_anim_cmd.complete_message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.complete_message(std::move(cmd_complete_message));
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
std::optional<spine_player_commands::add_empty_anim_cmd> parse_add_empty_anim_cmd(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
u32 cmd_track{0u};
|
||||
E2D_ASSERT(root.HasMember("track"));
|
||||
if ( !json_utils::try_parse_value(root["track"], cmd_track) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.track' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
spine_player_commands::add_empty_anim_cmd cmd(cmd_track);
|
||||
|
||||
if ( root.HasMember("delay") ) {
|
||||
f32 cmd_delay = cmd.delay();
|
||||
if ( !json_utils::try_parse_value(root["delay"], cmd_delay) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.delay' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.delay(cmd_delay);
|
||||
}
|
||||
|
||||
if ( root.HasMember("mix_duration") ) {
|
||||
f32 cmd_mix_duration = cmd.mix_duration();
|
||||
if ( !json_utils::try_parse_value(root["mix_duration"], cmd_mix_duration) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.mix_duration' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.mix_duration(cmd_mix_duration);
|
||||
}
|
||||
|
||||
if ( root.HasMember("end_message") ) {
|
||||
str cmd_end_message = cmd.end_message();
|
||||
if ( !json_utils::try_parse_value(root["end_message"], cmd_end_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.end_message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.end_message(std::move(cmd_end_message));
|
||||
}
|
||||
|
||||
if ( root.HasMember("complete_message") ) {
|
||||
str cmd_complete_message = cmd.complete_message();
|
||||
if ( !json_utils::try_parse_value(root["complete_message"], cmd_complete_message) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'add_empty_anim_cmd.complete_message' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
cmd.complete_message(std::move(cmd_complete_message));
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
std::optional<spine_player_commands::command> parse_command(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsObject());
|
||||
|
||||
str_hash command_type;
|
||||
E2D_ASSERT(root.HasMember("type") && root["type"].IsString());
|
||||
if ( !json_utils::try_parse_value(root["type"], command_type) ) {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'command.type' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
E2D_ASSERT(root.HasMember("desc") && root["desc"].IsObject());
|
||||
const auto& command_desc = root["desc"];
|
||||
|
||||
if ( command_type == make_hash("clear_track_cmd") ) {
|
||||
auto cmd = parse_clear_track_cmd(command_desc);
|
||||
return cmd ? cmd : std::nullopt;
|
||||
} else if ( command_type == make_hash("set_anim_cmd") ) {
|
||||
auto cmd = parse_set_anim_cmd(command_desc);
|
||||
return cmd ? cmd : std::nullopt;
|
||||
} else if ( command_type == make_hash("add_anim_cmd") ) {
|
||||
auto cmd = parse_add_anim_cmd(command_desc);
|
||||
return cmd ? cmd : std::nullopt;
|
||||
} else if ( command_type == make_hash("set_empty_anim_cmd") ) {
|
||||
auto cmd = parse_set_empty_anim_cmd(command_desc);
|
||||
return cmd ? cmd : std::nullopt;
|
||||
} else if ( command_type == make_hash("add_empty_anim_cmd") ) {
|
||||
auto cmd = parse_add_empty_anim_cmd(command_desc);
|
||||
return cmd ? cmd : std::nullopt;
|
||||
} else {
|
||||
the<debug>().error("SPINE_PLAYER_COMMANDS: Incorrect formatting of 'command.type' property");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<vector<spine_player_commands::command>> parse_commands(const rapidjson::Value& root) {
|
||||
E2D_ASSERT(root.IsArray());
|
||||
|
||||
vector<spine_player_commands::command> cmds;
|
||||
cmds.reserve(root.Size());
|
||||
|
||||
for ( rapidjson::SizeType i = 0; i < root.Size(); ++i ) {
|
||||
auto cmd = parse_command(root[i]);
|
||||
if ( !cmd ) {
|
||||
return std::nullopt;
|
||||
}
|
||||
cmds.push_back(std::move(*cmd));
|
||||
}
|
||||
|
||||
return cmds;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
spine_player::spine_player(const spine_asset::ptr& spine) {
|
||||
this->spine(spine);
|
||||
}
|
||||
|
||||
spine_player& spine_player::spine(const spine_asset::ptr& value) {
|
||||
clipping_ptr new_clipping = clipping_ptr(
|
||||
spSkeletonClipping_create(),
|
||||
spSkeletonClipping_dispose);
|
||||
if ( !new_clipping ) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
skeleton_ptr new_skeleton;
|
||||
if ( value && value->content().skeleton() ) {
|
||||
new_skeleton = skeleton_ptr(
|
||||
spSkeleton_create(value->content().skeleton().get()),
|
||||
spSkeleton_dispose);
|
||||
if ( !new_skeleton ) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
animation_ptr new_animation;
|
||||
if ( value && value->content().animation() ) {
|
||||
new_animation = animation_ptr(
|
||||
spAnimationState_create(value->content().animation().get()),
|
||||
spAnimationState_dispose);
|
||||
if ( !new_animation ) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
spine_ = value;
|
||||
clipping_ = std::move(new_clipping);
|
||||
skeleton_ = std::move(new_skeleton);
|
||||
animation_ = std::move(new_animation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool spine_player::skin(str_view name) {
|
||||
if ( !skeleton_ ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static thread_local str skin_name;
|
||||
skin_name = name;
|
||||
|
||||
return !!spSkeleton_setSkinByName(
|
||||
skeleton_.get(), skin_name.c_str());
|
||||
}
|
||||
|
||||
bool spine_player::attachment(str_view slot, str_view name) {
|
||||
if ( !skeleton_ ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static thread_local str slot_name;
|
||||
slot_name = slot;
|
||||
|
||||
static thread_local str attachment_name;
|
||||
attachment_name = name;
|
||||
|
||||
return !!spSkeleton_setAttachment(
|
||||
skeleton_.get(), slot_name.c_str(), attachment_name.c_str());
|
||||
}
|
||||
|
||||
bool spine_player::has_skin(str_view name) const noexcept {
|
||||
if ( !skeleton_ ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < skeleton_->data->skinsCount; ++i ) {
|
||||
if ( name == skeleton_->data->skins[i]->name ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spine_player::has_animation(str_view name) const noexcept {
|
||||
if ( !skeleton_ ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < skeleton_->data->animationsCount; ++i ) {
|
||||
if ( name == skeleton_->data->animations[i]->name ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const spine_asset::ptr& spine_player::spine() const noexcept {
|
||||
return spine_;
|
||||
}
|
||||
|
||||
const spine_player::clipping_ptr& spine_player::clipper() const noexcept {
|
||||
return clipping_;
|
||||
}
|
||||
|
||||
const spine_player::skeleton_ptr& spine_player::skeleton() const noexcept {
|
||||
return skeleton_;
|
||||
}
|
||||
|
||||
const spine_player::animation_ptr& spine_player::animation() const noexcept {
|
||||
return animation_;
|
||||
}
|
||||
|
||||
spine_player& spine_player::materials(flat_map<str_hash, material_asset::ptr> value) noexcept {
|
||||
materials_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const flat_map<str_hash, material_asset::ptr>& spine_player::materials() const noexcept {
|
||||
return materials_;
|
||||
}
|
||||
|
||||
material_asset::ptr spine_player::find_material(str_hash name) const noexcept {
|
||||
const auto iter = materials_.find(name);
|
||||
return iter != materials_.end()
|
||||
? iter->second
|
||||
: nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
const char* factory_loader<spine_player>::schema_source = R"json({
|
||||
"type" : "object",
|
||||
"required" : [],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"spine" : { "$ref": "#/common_definitions/address" },
|
||||
"materials" : { "$ref": "#/definitions/materials" },
|
||||
"skin" : { "$ref": "#/common_definitions/name" },
|
||||
"attachments" : { "$ref": "#/definitions/attachments" }
|
||||
},
|
||||
"definitions" : {
|
||||
"materials" : {
|
||||
"type" : "object",
|
||||
"required" : [],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"normal" : { "$ref": "#/common_definitions/address" },
|
||||
"additive" : { "$ref": "#/common_definitions/address" },
|
||||
"multiply" : { "$ref": "#/common_definitions/address" },
|
||||
"screen" : { "$ref": "#/common_definitions/address" }
|
||||
}
|
||||
},
|
||||
"attachments" : {
|
||||
"type" : "array",
|
||||
"items" : { "$ref": "#/definitions/attachment" }
|
||||
},
|
||||
"attachment" : {
|
||||
"type" : "object",
|
||||
"required" : [ "slot", "name" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"slot" : { "$ref": "#/common_definitions/name" },
|
||||
"name" : { "$ref": "#/common_definitions/name" }
|
||||
}
|
||||
}
|
||||
}
|
||||
})json";
|
||||
|
||||
bool factory_loader<spine_player>::operator()(
|
||||
spine_player& component,
|
||||
const fill_context& ctx) const
|
||||
{
|
||||
if ( ctx.root.HasMember("spine") ) {
|
||||
auto spine = ctx.dependencies.find_asset<spine_asset>(
|
||||
path::combine(ctx.parent_address, ctx.root["spine"].GetString()));
|
||||
if ( !spine ) {
|
||||
the<debug>().error("SPINE_PLAYER: Dependency 'spine' is not found:\n"
|
||||
"--> Parent address: %0\n"
|
||||
"--> Dependency address: %1",
|
||||
ctx.parent_address,
|
||||
ctx.root["spine"].GetString());
|
||||
return false;
|
||||
}
|
||||
component.spine(spine);
|
||||
}
|
||||
|
||||
if ( ctx.root.HasMember("materials") ) {
|
||||
const rapidjson::Value& materials_root = ctx.root["materials"];
|
||||
flat_map<str_hash, material_asset::ptr> materials;
|
||||
materials.reserve(materials_root.MemberCount());
|
||||
for ( rapidjson::Value::ConstMemberIterator material_root = materials_root.MemberBegin();
|
||||
material_root != materials_root.MemberEnd();
|
||||
++material_root )
|
||||
{
|
||||
str_hash material_name;
|
||||
if ( !json_utils::try_parse_value(material_root->name, material_name) ) {
|
||||
the<debug>().error("SPINE_PLAYER: Incorrect formatting of 'material.name' property");
|
||||
return false;
|
||||
}
|
||||
|
||||
str material_address;
|
||||
if ( !json_utils::try_parse_value(material_root->value, material_address) ) {
|
||||
the<debug>().error("SPINE_PLAYER: Incorrect formatting of 'material.address' property");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto material = ctx.dependencies.find_asset<material_asset>(
|
||||
path::combine(ctx.parent_address, material_address));
|
||||
if ( !material ) {
|
||||
the<debug>().error("SPINE_PLAYER: Dependency 'material' is not found:\n"
|
||||
"--> Parent address: %0\n"
|
||||
"--> Dependency address: %1",
|
||||
ctx.parent_address,
|
||||
material_address);
|
||||
return false;
|
||||
}
|
||||
materials.emplace(material_name, material);
|
||||
}
|
||||
component.materials(std::move(materials));
|
||||
}
|
||||
|
||||
if ( ctx.root.HasMember("skin") ) {
|
||||
str skin;
|
||||
if ( !json_utils::try_parse_value(ctx.root["skin"], skin) ) {
|
||||
the<debug>().error("SPINE_PLAYER: Incorrect formatting of 'skin' property");
|
||||
return false;
|
||||
}
|
||||
component.skin(skin);
|
||||
}
|
||||
|
||||
if ( ctx.root.HasMember("attachments") ) {
|
||||
const auto& attachments_json = ctx.root["attachments"];
|
||||
E2D_ASSERT(attachments_json.IsArray());
|
||||
|
||||
for ( rapidjson::SizeType i = 0; i < attachments_json.Size(); ++i ) {
|
||||
E2D_ASSERT(attachments_json[i].IsObject());
|
||||
const auto& attachment_json = attachments_json[i];
|
||||
|
||||
str slot;
|
||||
E2D_ASSERT(attachment_json.HasMember("slot"));
|
||||
if ( !json_utils::try_parse_value(attachment_json["slot"], slot) ) {
|
||||
the<debug>().error("SPINE_PLAYER: Incorrect formatting of 'attachment.slot' property");
|
||||
return false;
|
||||
}
|
||||
|
||||
str name;
|
||||
E2D_ASSERT(attachment_json.HasMember("name"));
|
||||
if ( !json_utils::try_parse_value(attachment_json["name"], name) ) {
|
||||
the<debug>().error("SPINE_PLAYER: Incorrect formatting of 'attachment.name' property");
|
||||
return false;
|
||||
}
|
||||
|
||||
component.attachment(slot, name);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool factory_loader<spine_player>::operator()(
|
||||
asset_dependencies& dependencies,
|
||||
const collect_context& ctx) const
|
||||
{
|
||||
if ( ctx.root.HasMember("spine") ) {
|
||||
dependencies.add_dependency<spine_asset>(
|
||||
path::combine(ctx.parent_address, ctx.root["spine"].GetString()));
|
||||
}
|
||||
|
||||
if ( ctx.root.HasMember("materials") ) {
|
||||
const rapidjson::Value& materials_root = ctx.root["materials"];
|
||||
for ( rapidjson::Value::ConstMemberIterator material_root = materials_root.MemberBegin();
|
||||
material_root != materials_root.MemberEnd();
|
||||
++material_root )
|
||||
{
|
||||
dependencies.add_dependency<material_asset>(
|
||||
path::combine(ctx.parent_address, material_root->value.GetString()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
const char* factory_loader<events<spine_player_events::event>>::schema_source = R"json({
|
||||
"type" : "object",
|
||||
"required" : [],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"events" : { "$ref": "#/definitions/events" }
|
||||
},
|
||||
"definitions" : {
|
||||
"events" : {
|
||||
"type" : "array",
|
||||
"items" : { "$ref": "#/definitions/event" }
|
||||
},
|
||||
"event" : {
|
||||
"type" : "object",
|
||||
"required" : [ "type", "desc" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"type" : { "$ref": "#/common_definitions/name" },
|
||||
"desc" : {
|
||||
"anyOf" : [{
|
||||
"$ref" : "#/definitions/custom_evt"
|
||||
}, {
|
||||
"$ref" : "#/definitions/end"
|
||||
}, {
|
||||
"$ref" : "#/definitions/complete"
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"custom_evt" : {
|
||||
"type" : "object",
|
||||
"required" : [],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"name" : { "type" : "string" },
|
||||
"int_value" : { "type" : "integer" },
|
||||
"float_value" : { "type" : "number" },
|
||||
"string_value" : { "type" : "string" }
|
||||
}
|
||||
},
|
||||
"end" : {
|
||||
"type" : "object",
|
||||
"required" : [],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"message" : { "type" : "string" }
|
||||
}
|
||||
},
|
||||
"complete" : {
|
||||
"type" : "object",
|
||||
"required" : [],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"message" : { "type" : "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
})json";
|
||||
|
||||
bool factory_loader<events<spine_player_events::event>>::operator()(
|
||||
events<spine_player_events::event>& component,
|
||||
const fill_context& ctx) const
|
||||
{
|
||||
if ( ctx.root.HasMember("events") ) {
|
||||
auto evts = parse_events(ctx.root["events"]);
|
||||
|
||||
if ( !evts ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( auto& evt : *evts ) {
|
||||
if ( evt.valueless_by_exception() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
component.set(std::move(*evts));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool factory_loader<events<spine_player_events::event>>::operator()(
|
||||
asset_dependencies& dependencies,
|
||||
const collect_context& ctx) const
|
||||
{
|
||||
E2D_UNUSED(dependencies, ctx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
const char* factory_loader<commands<spine_player_commands::command>>::schema_source = R"json({
|
||||
"type" : "object",
|
||||
"required" : [],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"commands" : { "$ref": "#/definitions/commands" }
|
||||
},
|
||||
"definitions" : {
|
||||
"commands" : {
|
||||
"type" : "array",
|
||||
"items" : { "$ref": "#/definitions/command" }
|
||||
},
|
||||
"command" : {
|
||||
"type" : "object",
|
||||
"required" : [ "type", "desc" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"type" : { "$ref": "#/common_definitions/name" },
|
||||
"desc" : {
|
||||
"anyOf" : [{
|
||||
"$ref" : "#/definitions/clear_track_cmd"
|
||||
}, {
|
||||
"$ref" : "#/definitions/set_anim_cmd"
|
||||
}, {
|
||||
"$ref" : "#/definitions/add_anim_cmd"
|
||||
}, {
|
||||
"$ref" : "#/definitions/set_empty_anim_cmd"
|
||||
}, {
|
||||
"$ref" : "#/definitions/add_empty_anim_cmd"
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"clear_track_cmd" : {
|
||||
"type" : "object",
|
||||
"required" : [ "track" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"track" : { "type" : "integer", "minimum" : 0 }
|
||||
}
|
||||
},
|
||||
"set_anim_cmd" : {
|
||||
"type" : "object",
|
||||
"required" : [ "track", "name" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"track" : { "type" : "integer", "minimum" : 0 },
|
||||
"name" : { "$ref": "#/common_definitions/name" },
|
||||
"loop" : { "type" : "boolean" },
|
||||
"end_message" : { "type" : "string" },
|
||||
"complete_message" : { "type" : "string" }
|
||||
}
|
||||
},
|
||||
"add_anim_cmd" : {
|
||||
"type" : "object",
|
||||
"required" : [ "track", "name" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"track" : { "type" : "integer", "minimum" : 0 },
|
||||
"name" : { "$ref": "#/common_definitions/name" },
|
||||
"loop" : { "type" : "boolean" },
|
||||
"delay" : { "type" : "number" },
|
||||
"end_message" : { "type" : "string" },
|
||||
"complete_message" : { "type" : "string" }
|
||||
}
|
||||
},
|
||||
"set_empty_anim_cmd" : {
|
||||
"type" : "object",
|
||||
"required" : [ "track" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"track" : { "type" : "integer", "minimum" : 0 },
|
||||
"mix_duration" : { "type" : "number" },
|
||||
"end_message" : { "type" : "string" },
|
||||
"complete_message" : { "type" : "string" }
|
||||
}
|
||||
},
|
||||
"add_empty_anim_cmd" : {
|
||||
"type" : "object",
|
||||
"required" : [ "track" ],
|
||||
"additionalProperties" : false,
|
||||
"properties" : {
|
||||
"track" : { "type" : "integer", "minimum" : 0 },
|
||||
"delay" : { "type" : "number" },
|
||||
"mix_duration" : { "type" : "number" },
|
||||
"end_message" : { "type" : "string" },
|
||||
"complete_message" : { "type" : "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
})json";
|
||||
|
||||
bool factory_loader<commands<spine_player_commands::command>>::operator()(
|
||||
commands<spine_player_commands::command>& component,
|
||||
const fill_context& ctx) const
|
||||
{
|
||||
if ( ctx.root.HasMember("commands") ) {
|
||||
auto cmds = parse_commands(ctx.root["commands"]);
|
||||
|
||||
if ( !cmds ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( auto& cmd : *cmds ) {
|
||||
if ( cmd.valueless_by_exception() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
component.set(std::move(*cmds));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool factory_loader<commands<spine_player_commands::command>>::operator()(
|
||||
asset_dependencies& dependencies,
|
||||
const collect_context& ctx) const
|
||||
{
|
||||
E2D_UNUSED(dependencies, ctx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
const char* component_inspector<spine_player>::title = ICON_FA_PARAGRAPH " spine_player";
|
||||
|
||||
void component_inspector<spine_player>::operator()(gcomponent<spine_player>& c) const {
|
||||
E2D_UNUSED(c);
|
||||
///TODO(BlackMat): add 'spine' inspector
|
||||
///TODO(BlackMat): add 'materials' inspector
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <enduro2d/high/resources/spine.hpp>
|
||||
|
||||
#include <spine/spine.h>
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
spine::spine(spine&& other) noexcept {
|
||||
assign(std::move(other));
|
||||
}
|
||||
|
||||
spine& spine::operator=(spine&& other) noexcept {
|
||||
return assign(std::move(other));
|
||||
}
|
||||
|
||||
spine::spine(const spine& other) {
|
||||
assign(other);
|
||||
}
|
||||
|
||||
spine& spine::operator=(const spine& other) {
|
||||
return assign(other);
|
||||
}
|
||||
|
||||
void spine::clear() noexcept {
|
||||
atlas_.reset();
|
||||
skeleton_.reset();
|
||||
animation_.reset();
|
||||
}
|
||||
|
||||
void spine::swap(spine& other) noexcept {
|
||||
using std::swap;
|
||||
swap(atlas_, other.atlas_);
|
||||
swap(skeleton_, other.skeleton_);
|
||||
swap(animation_, other.animation_);
|
||||
}
|
||||
|
||||
spine& spine::assign(spine&& other) noexcept {
|
||||
if ( this != &other ) {
|
||||
swap(other);
|
||||
other.clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
spine& spine::assign(const spine& other) {
|
||||
if ( this != &other ) {
|
||||
spine m;
|
||||
m.atlas_ = other.atlas_;
|
||||
m.skeleton_ = other.skeleton_;
|
||||
m.animation_ = other.animation_;
|
||||
swap(m);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
spine& spine::set_atlas(atlas_ptr atlas) {
|
||||
atlas_ = std::move(atlas);
|
||||
return *this;
|
||||
}
|
||||
|
||||
spine& spine::set_skeleton(skeleton_data_ptr skeleton) {
|
||||
animation_data_ptr animation;
|
||||
if ( skeleton ) {
|
||||
animation.reset(
|
||||
spAnimationStateData_create(skeleton.get()),
|
||||
spAnimationStateData_dispose);
|
||||
if ( !animation ) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
skeleton_ = std::move(skeleton);
|
||||
animation_ = std::move(animation);
|
||||
return *this;
|
||||
}
|
||||
|
||||
spine& spine::set_default_mix(f32 duration) {
|
||||
if ( !animation_ ) {
|
||||
throw bad_spine_access();
|
||||
}
|
||||
animation_->defaultMix = duration;
|
||||
return *this;
|
||||
}
|
||||
|
||||
spine& spine::set_animation_mix(
|
||||
const str& from,
|
||||
const str& to,
|
||||
f32 duration)
|
||||
{
|
||||
spAnimation* from_anim = animation_
|
||||
? spSkeletonData_findAnimation(animation_->skeletonData, from.c_str())
|
||||
: nullptr;
|
||||
|
||||
spAnimation* to_anim = animation_
|
||||
? spSkeletonData_findAnimation(animation_->skeletonData, to.c_str())
|
||||
: nullptr;
|
||||
|
||||
if ( !from_anim || !to_anim ) {
|
||||
throw bad_spine_access();
|
||||
}
|
||||
|
||||
spAnimationStateData_setMix(animation_.get(), from_anim, to_anim, duration);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const spine::atlas_ptr& spine::atlas() const noexcept {
|
||||
return atlas_;
|
||||
}
|
||||
|
||||
const spine::skeleton_data_ptr& spine::skeleton() const noexcept {
|
||||
return skeleton_;
|
||||
}
|
||||
|
||||
const spine::animation_data_ptr& spine::animation() const noexcept {
|
||||
return animation_;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
void swap(spine& l, spine& r) noexcept {
|
||||
l.swap(r);
|
||||
}
|
||||
|
||||
bool operator==(const spine& l, const spine& r) noexcept {
|
||||
return l.atlas() == r.atlas()
|
||||
&& l.skeleton() == r.skeleton()
|
||||
&& l.animation() == r.animation();
|
||||
}
|
||||
|
||||
bool operator!=(const spine& l, const spine& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <enduro2d/high/components/named.hpp>
|
||||
#include <enduro2d/high/components/renderer.hpp>
|
||||
#include <enduro2d/high/components/scene.hpp>
|
||||
#include <enduro2d/high/components/spine_player.hpp>
|
||||
#include <enduro2d/high/components/sprite_renderer.hpp>
|
||||
#include <enduro2d/high/components/touchable.hpp>
|
||||
#include <enduro2d/high/components/widget.hpp>
|
||||
@@ -37,7 +36,6 @@
|
||||
#include <enduro2d/high/systems/label_system.hpp>
|
||||
#include <enduro2d/high/systems/layout_system.hpp>
|
||||
#include <enduro2d/high/systems/render_system.hpp>
|
||||
#include <enduro2d/high/systems/spine_system.hpp>
|
||||
#include <enduro2d/high/systems/touch_system.hpp>
|
||||
#include <enduro2d/high/systems/widget_system.hpp>
|
||||
#include <enduro2d/high/systems/world_system.hpp>
|
||||
@@ -74,8 +72,6 @@ namespace
|
||||
.add_system<layout_system>())
|
||||
.feature<struct render_feature>(ecs::feature()
|
||||
.add_system<render_system>())
|
||||
.feature<struct spine_feature>(ecs::feature()
|
||||
.add_system<spine_system>())
|
||||
.feature<struct touch_feature>(ecs::feature()
|
||||
.add_system<touch_system>())
|
||||
.feature<struct widget_feature>(ecs::feature()
|
||||
@@ -198,9 +194,6 @@ namespace e2d
|
||||
.register_component<named>("named")
|
||||
.register_component<renderer>("renderer")
|
||||
.register_component<scene>("scene")
|
||||
.register_component<spine_player>("spine_player")
|
||||
.register_component<events<spine_player_events::event>>("spine_player.events")
|
||||
.register_component<commands<spine_player_commands::command>>("spine_player.commands")
|
||||
.register_component<sprite_renderer>("sprite_renderer")
|
||||
.register_component<touchable>("touchable")
|
||||
.register_component<events<touchable_events::event>>("touchable.events")
|
||||
@@ -225,9 +218,6 @@ namespace e2d
|
||||
.register_component<named>("named")
|
||||
.register_component<renderer>("renderer")
|
||||
.register_component<scene>("scene")
|
||||
.register_component<spine_player>("spine_player")
|
||||
//.register_component<events<spine_player_events::event>>("spine_player.events")
|
||||
//.register_component<commands<spine_player_commands::command>>("spine_player.commands")
|
||||
.register_component<sprite_renderer>("sprite_renderer")
|
||||
.register_component<touchable>("touchable")
|
||||
//.register_component<events<touchable_events::event>>("touchable.events")
|
||||
|
||||
@@ -9,11 +9,8 @@
|
||||
#include <enduro2d/high/components/disabled.hpp>
|
||||
#include <enduro2d/high/components/model_renderer.hpp>
|
||||
#include <enduro2d/high/components/renderer.hpp>
|
||||
#include <enduro2d/high/components/spine_player.hpp>
|
||||
#include <enduro2d/high/components/sprite_renderer.hpp>
|
||||
|
||||
#include <spine/spine.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
@@ -103,10 +100,6 @@ namespace e2d::render_system_impl
|
||||
draw(model_m, *node_r, *mdl_r);
|
||||
}
|
||||
|
||||
if ( auto spn_p = gcomponent<spine_player>{owner} ) {
|
||||
draw(model_m, *node_r, *spn_p);
|
||||
}
|
||||
|
||||
if ( auto spr_r = gcomponent<sprite_renderer>{owner} ) {
|
||||
draw(model_m, *node_r, *spr_r);
|
||||
}
|
||||
@@ -155,276 +148,6 @@ namespace e2d::render_system_impl
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::context::draw(
|
||||
const m4f& model_m,
|
||||
const renderer& node_r,
|
||||
const spine_player& spine_r)
|
||||
{
|
||||
//TODO(BlackMat): replace it to frame allocator
|
||||
static thread_local std::vector<float> temp_vertices(1000u, 0.f);
|
||||
static thread_local std::vector<batcher_type::vertex_type> batch_vertices(1000u);
|
||||
|
||||
spSkeleton* skeleton = spine_r.skeleton().get();
|
||||
spSkeletonClipping* clipper = spine_r.clipper().get();
|
||||
|
||||
if ( !skeleton || !clipper ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( math::is_near_zero(skeleton->color.a) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
material_asset::ptr normal_mat_a;
|
||||
material_asset::ptr additive_mat_a;
|
||||
material_asset::ptr multiply_mat_a;
|
||||
material_asset::ptr screen_mat_a;
|
||||
|
||||
unsigned short quad_indices[6] = { 0, 1, 2, 2, 3, 0 };
|
||||
|
||||
DEFER([this, clipper](){
|
||||
property_cache_.clear();
|
||||
spSkeletonClipping_clipEnd2(clipper);
|
||||
});
|
||||
|
||||
for ( int i = 0; i < skeleton->slotsCount; ++i ) {
|
||||
spSlot* slot = skeleton->drawOrder[i];
|
||||
|
||||
auto slot_clipping_defer = defer_hpp::make_defer([clipper, slot](){
|
||||
spSkeletonClipping_clipEnd(clipper, slot);
|
||||
});
|
||||
|
||||
spAttachment* attachment = slot->attachment;
|
||||
if ( !attachment || math::is_near_zero(slot->color.a) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float* uvs = nullptr;
|
||||
unsigned short* indices = nullptr;
|
||||
int index_count = 0;
|
||||
int vertex_count = 0;
|
||||
const spAtlasPage* atlas_page = nullptr;
|
||||
const spColor* attachment_color = nullptr;
|
||||
|
||||
if ( attachment->type == SP_ATTACHMENT_REGION ) {
|
||||
spRegionAttachment* region = reinterpret_cast<spRegionAttachment*>(attachment);
|
||||
|
||||
attachment_color = ®ion->color;
|
||||
if ( math::is_near_zero(attachment_color->a) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
vertex_count = 8;
|
||||
if ( temp_vertices.size() < math::numeric_cast<std::size_t>(vertex_count) ) {
|
||||
temp_vertices.resize(math::max(
|
||||
temp_vertices.size() * 2u,
|
||||
math::numeric_cast<std::size_t>(vertex_count)));
|
||||
}
|
||||
}
|
||||
|
||||
spRegionAttachment_computeWorldVertices(
|
||||
region,
|
||||
slot->bone,
|
||||
temp_vertices.data(),
|
||||
0, 2);
|
||||
|
||||
uvs = region->uvs;
|
||||
indices = quad_indices;
|
||||
index_count = 6;
|
||||
atlas_page = static_cast<spAtlasRegion*>(region->rendererObject)->page;
|
||||
} else if ( attachment->type == SP_ATTACHMENT_MESH ) {
|
||||
spMeshAttachment* mesh = reinterpret_cast<spMeshAttachment*>(attachment);
|
||||
|
||||
attachment_color = &mesh->color;
|
||||
if ( math::is_near_zero(attachment_color->a) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
vertex_count = mesh->super.worldVerticesLength;
|
||||
if ( temp_vertices.size() < math::numeric_cast<std::size_t>(vertex_count) ) {
|
||||
temp_vertices.resize(math::max(
|
||||
temp_vertices.size() * 2u,
|
||||
math::numeric_cast<std::size_t>(vertex_count)));
|
||||
}
|
||||
}
|
||||
|
||||
spVertexAttachment_computeWorldVertices(
|
||||
&mesh->super,
|
||||
slot,
|
||||
0,
|
||||
mesh->super.worldVerticesLength,
|
||||
temp_vertices.data(),
|
||||
0, 2);
|
||||
|
||||
uvs = mesh->uvs;
|
||||
indices = mesh->triangles;
|
||||
index_count = mesh->trianglesCount;
|
||||
atlas_page = static_cast<spAtlasRegion*>(mesh->rendererObject)->page;
|
||||
} else if ( attachment->type == SP_ATTACHMENT_CLIPPING ) {
|
||||
spClippingAttachment* clip = reinterpret_cast<spClippingAttachment*>(attachment);
|
||||
spSkeletonClipping_clipStart(clipper, slot, clip);
|
||||
slot_clipping_defer.dismiss();
|
||||
continue;
|
||||
} else {
|
||||
slot_clipping_defer.dismiss();
|
||||
continue;
|
||||
}
|
||||
|
||||
color32 vert_color = color32(
|
||||
color(skeleton->color.r, skeleton->color.g, skeleton->color.b, skeleton->color.a) *
|
||||
color(slot->color.r, slot->color.g, slot->color.b, slot->color.a) *
|
||||
color(attachment_color->r, attachment_color->g, attachment_color->b, attachment_color->a));
|
||||
|
||||
texture_ptr tex_p;
|
||||
const texture_asset* texture_asset_ptr = atlas_page
|
||||
? static_cast<const texture_asset*>(atlas_page->rendererObject)
|
||||
: nullptr;
|
||||
if ( texture_asset_ptr ) {
|
||||
tex_p = texture_asset_ptr->content();
|
||||
}
|
||||
|
||||
render::sampler_min_filter tex_min_f = render::sampler_min_filter::linear;
|
||||
if ( atlas_page ) {
|
||||
switch ( atlas_page->minFilter ) {
|
||||
case SP_ATLAS_NEAREST:
|
||||
case SP_ATLAS_MIPMAP_NEAREST_LINEAR:
|
||||
case SP_ATLAS_MIPMAP_NEAREST_NEAREST:
|
||||
tex_min_f = render::sampler_min_filter::nearest;
|
||||
break;
|
||||
default:
|
||||
tex_min_f = render::sampler_min_filter::linear;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
render::sampler_mag_filter tex_mag_f = render::sampler_mag_filter::linear;
|
||||
if ( atlas_page ) {
|
||||
switch ( atlas_page->magFilter ) {
|
||||
case SP_ATLAS_NEAREST:
|
||||
case SP_ATLAS_MIPMAP_NEAREST_LINEAR:
|
||||
case SP_ATLAS_MIPMAP_NEAREST_NEAREST:
|
||||
tex_mag_f = render::sampler_mag_filter::nearest;
|
||||
break;
|
||||
default:
|
||||
tex_mag_f = render::sampler_mag_filter::linear;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
render::sampler_wrap tex_wrap_s = render::sampler_wrap::repeat;
|
||||
if ( atlas_page ) {
|
||||
switch ( atlas_page->uWrap ) {
|
||||
case SP_ATLAS_MIRROREDREPEAT:
|
||||
tex_wrap_s = render::sampler_wrap::mirror;
|
||||
break;
|
||||
case SP_ATLAS_CLAMPTOEDGE:
|
||||
tex_wrap_s = render::sampler_wrap::clamp;
|
||||
break;
|
||||
case SP_ATLAS_REPEAT:
|
||||
tex_wrap_s = render::sampler_wrap::repeat;
|
||||
break;
|
||||
default:
|
||||
E2D_ASSERT_MSG(false, "unexpected wrap mode for slot");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
render::sampler_wrap tex_wrap_t = render::sampler_wrap::repeat;
|
||||
if ( atlas_page ) {
|
||||
switch ( atlas_page->vWrap ) {
|
||||
case SP_ATLAS_MIRROREDREPEAT:
|
||||
tex_wrap_t = render::sampler_wrap::mirror;
|
||||
break;
|
||||
case SP_ATLAS_CLAMPTOEDGE:
|
||||
tex_wrap_t = render::sampler_wrap::clamp;
|
||||
break;
|
||||
case SP_ATLAS_REPEAT:
|
||||
tex_wrap_t = render::sampler_wrap::repeat;
|
||||
break;
|
||||
default:
|
||||
E2D_ASSERT_MSG(false, "unexpected wrap mode for slot");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
material_asset::ptr mat_a;
|
||||
switch ( slot->data->blendMode ) {
|
||||
case SP_BLEND_MODE_NORMAL:
|
||||
mat_a = normal_mat_a
|
||||
? normal_mat_a
|
||||
: (normal_mat_a = spine_r.find_material(normal_material_hash));
|
||||
break;
|
||||
case SP_BLEND_MODE_ADDITIVE:
|
||||
mat_a = additive_mat_a
|
||||
? additive_mat_a
|
||||
: (additive_mat_a = spine_r.find_material(additive_material_hash));
|
||||
break;
|
||||
case SP_BLEND_MODE_MULTIPLY:
|
||||
mat_a = multiply_mat_a
|
||||
? multiply_mat_a
|
||||
: (multiply_mat_a = spine_r.find_material(multiply_material_hash));
|
||||
break;
|
||||
case SP_BLEND_MODE_SCREEN:
|
||||
mat_a = screen_mat_a
|
||||
? screen_mat_a
|
||||
: (screen_mat_a = spine_r.find_material(screen_material_hash));
|
||||
break;
|
||||
default:
|
||||
E2D_ASSERT_MSG(false, "unexpected blend mode for slot");
|
||||
break;
|
||||
}
|
||||
|
||||
if ( math::is_near_zero(vert_color.a) || !tex_p || !mat_a ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float* vertices = temp_vertices.data();
|
||||
if ( spSkeletonClipping_isClipping(clipper) ) {
|
||||
spSkeletonClipping_clipTriangles(
|
||||
clipper,
|
||||
temp_vertices.data(), vertex_count,
|
||||
indices, index_count,
|
||||
uvs,
|
||||
2);
|
||||
vertices = clipper->clippedVertices->items;
|
||||
vertex_count = clipper->clippedVertices->size;
|
||||
uvs = clipper->clippedUVs->items;
|
||||
indices = clipper->clippedTriangles->items;
|
||||
index_count = clipper->clippedTriangles->size;
|
||||
}
|
||||
|
||||
{
|
||||
const std::size_t batch_vertex_count = vertex_count >> 1;
|
||||
|
||||
if ( batch_vertices.size() < batch_vertex_count ) {
|
||||
batch_vertices.resize(math::max(batch_vertices.size() * 2u, batch_vertex_count));
|
||||
}
|
||||
|
||||
for ( std::size_t j = 0; j < batch_vertex_count; ++j ) {
|
||||
batcher_type::vertex_type& vert = batch_vertices[j];
|
||||
vert.v = v3f(v4f(vertices[j * 2], vertices[j * 2 + 1], 0.f, 1.f) * model_m);
|
||||
vert.t = v2f(uvs[j * 2], uvs[j * 2 + 1]);
|
||||
vert.c = vert_color;
|
||||
}
|
||||
|
||||
property_cache_
|
||||
.sampler(texture_sampler_hash, render::sampler_state()
|
||||
.texture(tex_p)
|
||||
.filter(tex_min_f, tex_mag_f)
|
||||
.wrap(tex_wrap_s, tex_wrap_t))
|
||||
.merge(node_r.properties());
|
||||
|
||||
batcher_.batch(
|
||||
mat_a,
|
||||
property_cache_,
|
||||
indices, math::numeric_cast<std::size_t>(index_count),
|
||||
batch_vertices.data(), batch_vertex_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawer::context::draw(
|
||||
const m4f& model_m,
|
||||
const renderer& node_r,
|
||||
|
||||
@@ -51,11 +51,6 @@ namespace e2d::render_system_impl
|
||||
const m4f& model_m,
|
||||
const renderer& node_r,
|
||||
const sprite_renderer& spr_r);
|
||||
|
||||
void draw(
|
||||
const m4f& model_m,
|
||||
const renderer& node_r,
|
||||
const spine_player& spine_r);
|
||||
private:
|
||||
render& render_;
|
||||
batcher_type& batcher_;
|
||||
|
||||
@@ -1,263 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2020, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <enduro2d/high/systems/spine_system.hpp>
|
||||
|
||||
#include <enduro2d/high/components/events.hpp>
|
||||
#include <enduro2d/high/components/commands.hpp>
|
||||
#include <enduro2d/high/components/spine_player.hpp>
|
||||
|
||||
#include <spine/spine.h>
|
||||
|
||||
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_internal_state*>(entry->userData);
|
||||
|
||||
if ( type == SP_ANIMATION_DISPOSE || !entry_state.target.valid() ) {
|
||||
std::unique_ptr<entry_internal_state> entry_internal(&entry_state);
|
||||
entry->userData = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( type == SP_ANIMATION_EVENT ) {
|
||||
if ( !event || !event->data ) {
|
||||
return;
|
||||
}
|
||||
entry_state.target
|
||||
.ensure_component<events<spine_player_events::event>>()
|
||||
.add(spine_player_events::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<events<spine_player_events::event>>()
|
||||
.add(spine_player_events::end_evt(entry_state.end_message));
|
||||
} else if ( type == SP_ANIMATION_COMPLETE ) {
|
||||
if ( entry_state.complete_message.empty() ) {
|
||||
return;
|
||||
}
|
||||
entry_state.target
|
||||
.ensure_component<events<spine_player_events::event>>()
|
||||
.add(spine_player_events::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_commands::clear_track_cmd& cmd) const noexcept {
|
||||
spAnimationState_clearTrack(
|
||||
&animation_state_,
|
||||
math::numeric_cast<int>(cmd.track()));
|
||||
}
|
||||
|
||||
void operator()(const spine_player_commands::set_anim_cmd& cmd) const noexcept {
|
||||
spAnimation* animation = spSkeletonData_findAnimation(&skeleton_data_, cmd.name().c_str());
|
||||
if ( !animation ) {
|
||||
the<debug>().error("SPINE_POST_SYSTEM: animation '%0' is not found", cmd.name());
|
||||
return;
|
||||
}
|
||||
|
||||
auto entry_state = std::make_unique<entry_internal_state>(
|
||||
target_,
|
||||
cmd.end_message(),
|
||||
cmd.complete_message());
|
||||
|
||||
spTrackEntry* entry = spAnimationState_setAnimation(
|
||||
&animation_state_,
|
||||
math::numeric_cast<int>(cmd.track()),
|
||||
animation,
|
||||
cmd.loop() ? 1 : 0);
|
||||
|
||||
entry->listener = &entry_listener;
|
||||
entry->userData = entry_state.release();
|
||||
}
|
||||
|
||||
void operator()(const spine_player_commands::add_anim_cmd& cmd) const noexcept {
|
||||
spAnimation* animation = spSkeletonData_findAnimation(&skeleton_data_, cmd.name().c_str());
|
||||
if ( !animation ) {
|
||||
the<debug>().error("SPINE_POST_SYSTEM: animation '%0' is not found", cmd.name());
|
||||
return;
|
||||
}
|
||||
|
||||
auto entry_state = std::make_unique<entry_internal_state>(
|
||||
target_,
|
||||
cmd.end_message(),
|
||||
cmd.complete_message());
|
||||
|
||||
spTrackEntry* entry = spAnimationState_addAnimation(
|
||||
&animation_state_,
|
||||
math::numeric_cast<int>(cmd.track()),
|
||||
animation,
|
||||
cmd.loop() ? 1 : 0,
|
||||
cmd.delay());
|
||||
|
||||
entry->listener = &entry_listener;
|
||||
entry->userData = entry_state.release();
|
||||
}
|
||||
|
||||
void operator()(const spine_player_commands::set_empty_anim_cmd& cmd) const noexcept {
|
||||
auto entry_state = std::make_unique<entry_internal_state>(
|
||||
target_,
|
||||
cmd.end_message(),
|
||||
cmd.complete_message());
|
||||
|
||||
spTrackEntry* entry = spAnimationState_setEmptyAnimation(
|
||||
&animation_state_,
|
||||
math::numeric_cast<int>(cmd.track()),
|
||||
cmd.mix_duration());
|
||||
|
||||
entry->listener = &entry_listener;
|
||||
entry->userData = entry_state.release();
|
||||
}
|
||||
|
||||
void operator()(const spine_player_commands::add_empty_anim_cmd& cmd) const noexcept {
|
||||
auto entry_state = std::make_unique<entry_internal_state>(
|
||||
target_,
|
||||
cmd.end_message(),
|
||||
cmd.complete_message());
|
||||
|
||||
spTrackEntry* entry = spAnimationState_addEmptyAnimation(
|
||||
&animation_state_,
|
||||
math::numeric_cast<int>(cmd.track()),
|
||||
cmd.mix_duration(),
|
||||
cmd.delay());
|
||||
|
||||
entry->listener = &entry_listener;
|
||||
entry->userData = entry_state.release();
|
||||
}
|
||||
private:
|
||||
ecs::entity target_;
|
||||
spSkeletonData& skeleton_data_;
|
||||
spAnimationState& animation_state_;
|
||||
};
|
||||
|
||||
void clear_events(ecs::registry& owner) {
|
||||
owner.for_each_component<events<spine_player_events::event>>([
|
||||
](const ecs::const_entity&, events<spine_player_events::event>& es) {
|
||||
es.clear();
|
||||
});
|
||||
}
|
||||
|
||||
void update_animations(f32 dt, ecs::registry& owner) {
|
||||
owner.for_each_component<spine_player>([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);
|
||||
});
|
||||
}
|
||||
|
||||
void process_commands(ecs::registry& owner) {
|
||||
owner.for_joined_components<commands<spine_player_commands::command>, spine_player>([](
|
||||
ecs::entity e,
|
||||
const commands<spine_player_commands::command>& cs,
|
||||
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 : cs.get() ) {
|
||||
std::visit(v, cmd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void clear_commands(ecs::registry& owner) {
|
||||
owner.for_each_component<commands<spine_player_commands::command>>([
|
||||
](const ecs::const_entity&, commands<spine_player_commands::command>& cs) {
|
||||
cs.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
//
|
||||
// internal_state
|
||||
//
|
||||
|
||||
class spine_system::internal_state final {
|
||||
public:
|
||||
internal_state() = default;
|
||||
~internal_state() noexcept = default;
|
||||
|
||||
void process_update(f32 dt, ecs::registry& owner) {
|
||||
process_commands(owner);
|
||||
clear_commands(owner);
|
||||
clear_events(owner);
|
||||
update_animations(dt, owner);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// spine_system
|
||||
//
|
||||
|
||||
spine_system::spine_system()
|
||||
: state_(new internal_state()) {}
|
||||
|
||||
spine_system::~spine_system() noexcept {
|
||||
spAnimationState_disposeStatics();
|
||||
}
|
||||
|
||||
void spine_system::process(
|
||||
ecs::registry& owner,
|
||||
const ecs::after<systems::update_event>& trigger)
|
||||
{
|
||||
state_->process_update(trigger.event.dt, owner);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user