mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 01:06:00 +08:00
Additionally, CI builds were failing due to the commit where SpineSkin had an init() method added, but this caused Godot 3.x builds to fail. Our formatter was also run, so it should no longer fail the format check.
858 lines
29 KiB
C++
858 lines
29 KiB
C++
/******************************************************************************
|
|
* Spine Runtimes License Agreement
|
|
* Last updated April 5, 2025. Replaces all prior versions.
|
|
*
|
|
* Copyright (c) 2013-2025, Esoteric Software LLC
|
|
*
|
|
* Integration of the Spine Runtimes into software or otherwise creating
|
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
|
* http://esotericsoftware.com/spine-editor-license
|
|
*
|
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
|
* "Products"), provided that each user of the Products must obtain their own
|
|
* Spine Editor license and redistribution of the Products in any form must
|
|
* include this license and copyright notice.
|
|
*
|
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*****************************************************************************/
|
|
|
|
#include "SpineSkeletonDataResource.h"
|
|
#include "SpineCommon.h"
|
|
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
#include <godot_cpp/classes/encoded_object_as_id.hpp>
|
|
#include <godot_cpp/classes/engine.hpp>
|
|
#ifdef TOOLS_ENABLED
|
|
#include <godot_cpp/classes/editor_interface.hpp>
|
|
#endif
|
|
#else
|
|
#if VERSION_MAJOR > 3
|
|
#include "core/config/engine.h"
|
|
#ifdef TOOLS_ENABLED
|
|
#include "editor/editor_interface.h"
|
|
#endif
|
|
#else
|
|
#include "core/engine.h"
|
|
#endif
|
|
#include <core/io/marshalls.h>
|
|
#endif
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
#include <godot_cpp/classes/editor_file_system.hpp>
|
|
#else
|
|
#if (VERSION_MAJOR >= 4 && VERSION_MINOR >= 5)
|
|
#include "editor/file_system/editor_file_system.h"
|
|
#else
|
|
#include "editor/editor_file_system.h"
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
void SpineAnimationMix::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_from", "from"),
|
|
&SpineAnimationMix::set_from);
|
|
ClassDB::bind_method(D_METHOD("get_from"), &SpineAnimationMix::get_from);
|
|
ClassDB::bind_method(D_METHOD("set_to", "to"), &SpineAnimationMix::set_to);
|
|
ClassDB::bind_method(D_METHOD("get_to"), &SpineAnimationMix::get_to);
|
|
ClassDB::bind_method(D_METHOD("set_mix", "mix"), &SpineAnimationMix::set_mix);
|
|
ClassDB::bind_method(D_METHOD("get_mix"), &SpineAnimationMix::get_mix);
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "from"), "set_from", "get_from");
|
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "to"), "set_to", "get_to");
|
|
#if VERSION_MAJOR > 3
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mix"), "set_mix", "get_mix");
|
|
#else
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "mix"), "set_mix", "get_mix");
|
|
#endif
|
|
}
|
|
|
|
SpineAnimationMix::SpineAnimationMix() : from(""), to(""), mix(0) {}
|
|
|
|
void SpineAnimationMix::set_from(const String &_from) { this->from = _from; }
|
|
|
|
String SpineAnimationMix::get_from() { return from; }
|
|
|
|
void SpineAnimationMix::set_to(const String &_to) { this->to = _to; }
|
|
|
|
String SpineAnimationMix::get_to() { return to; }
|
|
|
|
void SpineAnimationMix::set_mix(float _mix) { this->mix = _mix; }
|
|
|
|
float SpineAnimationMix::get_mix() { return mix; }
|
|
|
|
void SpineSkeletonDataResource::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("is_skeleton_data_loaded"),
|
|
&SpineSkeletonDataResource::is_skeleton_data_loaded);
|
|
ClassDB::bind_method(D_METHOD("set_atlas_res", "atlas_res"),
|
|
&SpineSkeletonDataResource::set_atlas_res);
|
|
ClassDB::bind_method(D_METHOD("get_atlas_res"),
|
|
&SpineSkeletonDataResource::get_atlas_res);
|
|
ClassDB::bind_method(D_METHOD("set_skeleton_file_res", "skeleton_file_res"),
|
|
&SpineSkeletonDataResource::set_skeleton_file_res);
|
|
ClassDB::bind_method(D_METHOD("get_skeleton_file_res"),
|
|
&SpineSkeletonDataResource::get_skeleton_file_res);
|
|
ClassDB::bind_method(D_METHOD("set_default_mix", "default_mix"),
|
|
&SpineSkeletonDataResource::set_default_mix);
|
|
ClassDB::bind_method(D_METHOD("get_default_mix"),
|
|
&SpineSkeletonDataResource::get_default_mix);
|
|
ClassDB::bind_method(D_METHOD("set_animation_mixes", "mixes"),
|
|
&SpineSkeletonDataResource::set_animation_mixes);
|
|
ClassDB::bind_method(D_METHOD("get_animation_mixes"),
|
|
&SpineSkeletonDataResource::get_animation_mixes);
|
|
|
|
// Spine API
|
|
ClassDB::bind_method(D_METHOD("find_bone", "bone_name"),
|
|
&SpineSkeletonDataResource::find_bone);
|
|
ClassDB::bind_method(D_METHOD("find_slot", "slot_name"),
|
|
&SpineSkeletonDataResource::find_slot);
|
|
ClassDB::bind_method(D_METHOD("find_skin", "skin_name"),
|
|
&SpineSkeletonDataResource::find_skin);
|
|
ClassDB::bind_method(D_METHOD("find_event", "event_data_name"),
|
|
&SpineSkeletonDataResource::find_event);
|
|
ClassDB::bind_method(D_METHOD("find_animation", "animation_name"),
|
|
&SpineSkeletonDataResource::find_animation);
|
|
ClassDB::bind_method(D_METHOD("find_ik_constraint_data", "constraint_name"),
|
|
&SpineSkeletonDataResource::find_ik_constraint);
|
|
ClassDB::bind_method(
|
|
D_METHOD("find_transform_constraint_data", "constraint_name"),
|
|
&SpineSkeletonDataResource::find_transform_constraint);
|
|
ClassDB::bind_method(D_METHOD("find_path_constraint_data", "constraint_name"),
|
|
&SpineSkeletonDataResource::find_path_constraint);
|
|
ClassDB::bind_method(D_METHOD("find_physics_constraint_data", "constraint_name"),
|
|
&SpineSkeletonDataResource::find_physics_constraint);
|
|
ClassDB::bind_method(D_METHOD("get_skeleton_name"),
|
|
&SpineSkeletonDataResource::get_skeleton_name);
|
|
ClassDB::bind_method(D_METHOD("get_bones"),
|
|
&SpineSkeletonDataResource::get_bones);
|
|
ClassDB::bind_method(D_METHOD("get_slots"),
|
|
&SpineSkeletonDataResource::get_slots);
|
|
ClassDB::bind_method(D_METHOD("get_skins"),
|
|
&SpineSkeletonDataResource::get_skins);
|
|
ClassDB::bind_method(D_METHOD("get_default_skin"),
|
|
&SpineSkeletonDataResource::get_default_skin);
|
|
ClassDB::bind_method(D_METHOD("set_default_skin", "skin"),
|
|
&SpineSkeletonDataResource::set_default_skin);
|
|
ClassDB::bind_method(D_METHOD("get_events"),
|
|
&SpineSkeletonDataResource::get_events);
|
|
ClassDB::bind_method(D_METHOD("get_animations"),
|
|
&SpineSkeletonDataResource::get_animations);
|
|
ClassDB::bind_method(D_METHOD("get_ik_constraints"),
|
|
&SpineSkeletonDataResource::get_ik_constraints);
|
|
ClassDB::bind_method(D_METHOD("get_transform_constraints"),
|
|
&SpineSkeletonDataResource::get_transform_constraints);
|
|
ClassDB::bind_method(D_METHOD("get_path_constraints"),
|
|
&SpineSkeletonDataResource::get_path_constraints);
|
|
ClassDB::bind_method(D_METHOD("get_physics_constraints"),
|
|
&SpineSkeletonDataResource::get_physics_constraints);
|
|
ClassDB::bind_method(D_METHOD("get_x"), &SpineSkeletonDataResource::get_x);
|
|
ClassDB::bind_method(D_METHOD("get_y"), &SpineSkeletonDataResource::get_y);
|
|
ClassDB::bind_method(D_METHOD("get_width"),
|
|
&SpineSkeletonDataResource::get_width);
|
|
ClassDB::bind_method(D_METHOD("get_height"),
|
|
&SpineSkeletonDataResource::get_height);
|
|
ClassDB::bind_method(D_METHOD("get_version"),
|
|
&SpineSkeletonDataResource::get_version);
|
|
ClassDB::bind_method(D_METHOD("get_hash"),
|
|
&SpineSkeletonDataResource::get_hash);
|
|
ClassDB::bind_method(D_METHOD("get_images_path"),
|
|
&SpineSkeletonDataResource::get_images_path);
|
|
ClassDB::bind_method(D_METHOD("get_audio_path"),
|
|
&SpineSkeletonDataResource::get_audio_path);
|
|
ClassDB::bind_method(D_METHOD("get_fps"),
|
|
&SpineSkeletonDataResource::get_fps);
|
|
ClassDB::bind_method(D_METHOD("get_reference_scale"),
|
|
&SpineSkeletonDataResource::get_reference_scale);
|
|
ClassDB::bind_method(D_METHOD("set_reference_scale", "reference_scale"),
|
|
&SpineSkeletonDataResource::set_reference_scale);
|
|
ClassDB::bind_method(D_METHOD("update_skeleton_data"),
|
|
&SpineSkeletonDataResource::update_skeleton_data);
|
|
|
|
ADD_SIGNAL(MethodInfo("skeleton_data_changed"));
|
|
ADD_SIGNAL(MethodInfo("_internal_spine_objects_invalidated"));
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas_res",
|
|
PropertyHint::PROPERTY_HINT_RESOURCE_TYPE,
|
|
"SpineAtlasResource"),
|
|
"set_atlas_res", "get_atlas_res");
|
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skeleton_file_res",
|
|
PropertyHint::PROPERTY_HINT_RESOURCE_TYPE,
|
|
"SpineSkeletonFileResource"),
|
|
"set_skeleton_file_res", "get_skeleton_file_res");
|
|
#if VERSION_MAJOR > 3
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_mix"), "set_default_mix",
|
|
"get_default_mix");
|
|
#else
|
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "default_mix"), "set_default_mix",
|
|
"get_default_mix");
|
|
#endif
|
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animation_mixes"),
|
|
"set_animation_mixes", "get_animation_mixes");
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
#if VERSION_MAJOR > 3
|
|
ClassDB::bind_method(D_METHOD("_on_resources_reimported", "resources"),
|
|
&SpineSkeletonDataResource::_on_resources_reimported);
|
|
#else
|
|
ClassDB::bind_method(D_METHOD("_on_resources_reimported", "resources"),
|
|
&SpineSkeletonDataResource::_on_resources_reimported);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
EditorFileSystem *get_editor_file_system() {
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
EditorInterface *editor_interface = EditorInterface::get_singleton();
|
|
if (editor_interface) {
|
|
return editor_interface->get_resource_filesystem();
|
|
}
|
|
return nullptr;
|
|
#else
|
|
return EditorFileSystem::get_singleton();
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
SpineSkeletonDataResource::SpineSkeletonDataResource()
|
|
: default_mix(0), skeleton_data(nullptr), animation_state_data(nullptr) {
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
#if VERSION_MAJOR > 3
|
|
if (Engine::get_singleton()->is_editor_hint()) {
|
|
EditorFileSystem *efs = get_editor_file_system();
|
|
if (efs) {
|
|
// Store the ObjectID for safe validation in destructor
|
|
editor_file_system_id = efs->get_instance_id();
|
|
efs->connect("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported));
|
|
}
|
|
}
|
|
#else
|
|
if (Engine::get_singleton()->is_editor_hint()) {
|
|
EditorFileSystem *efs = EditorFileSystem::get_singleton();
|
|
if (efs) {
|
|
// Store the ObjectID for safe validation in destructor
|
|
editor_file_system_id = efs->get_instance_id();
|
|
efs->connect("resources_reimported", this, "_on_resources_reimported");
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
SpineSkeletonDataResource::~SpineSkeletonDataResource() {
|
|
#ifdef TOOLS_ENABLED
|
|
#if VERSION_MAJOR > 3
|
|
if (Engine::get_singleton()->is_editor_hint()) {
|
|
EditorFileSystem *efs = Object::cast_to<EditorFileSystem>(ObjectDB::get_instance(editor_file_system_id));
|
|
if (efs && efs->is_connected("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported))) {
|
|
efs->disconnect("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported));
|
|
}
|
|
}
|
|
#else
|
|
if (Engine::get_singleton()->is_editor_hint()) {
|
|
EditorFileSystem *efs = Object::cast_to<EditorFileSystem>(ObjectDB::get_instance(editor_file_system_id));
|
|
if (efs && efs->is_connected("resources_reimported", this, "_on_resources_reimported")) {
|
|
efs->disconnect("resources_reimported", this, "_on_resources_reimported");
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
delete skeleton_data;
|
|
delete animation_state_data;
|
|
}
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
#if VERSION_MAJOR > 3
|
|
void SpineSkeletonDataResource::_on_resources_reimported(const PackedStringArray &resources) {
|
|
for (int i = 0; i < resources.size(); i++) {
|
|
if (atlas_res.is_valid() && atlas_res->get_path() == resources[i]) {
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
atlas_res = ResourceLoader::get_singleton()->load(resources[i], "SpineAtlasResource", ResourceLoader::CACHE_MODE_IGNORE);
|
|
#else
|
|
atlas_res = ResourceLoader::load(resources[i], "SpineAtlasResource", ResourceFormatLoader::CACHE_MODE_IGNORE);
|
|
#endif
|
|
update_skeleton_data();
|
|
} else if (skeleton_file_res.is_valid() && skeleton_file_res->get_path() == resources[i]) {
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
skeleton_file_res = ResourceLoader::get_singleton()->load(resources[i], "SpineSkeletonFileResource", ResourceLoader::CACHE_MODE_IGNORE);
|
|
#else
|
|
skeleton_file_res = ResourceLoader::load(resources[i], "SpineSkeletonFileResource", ResourceFormatLoader::CACHE_MODE_IGNORE);
|
|
#endif
|
|
update_skeleton_data();
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
void SpineSkeletonDataResource::_on_resources_reimported(const PoolStringArray &resources) {
|
|
for (int i = 0; i < resources.size(); i++) {
|
|
if (atlas_res.is_valid() && atlas_res->get_path() == resources[i]) {
|
|
atlas_res = ResourceLoader::load(resources[i]);
|
|
update_skeleton_data();
|
|
} else if (skeleton_file_res.is_valid() && skeleton_file_res->get_path() == resources[i]) {
|
|
skeleton_file_res = ResourceLoader::load(resources[i]);
|
|
update_skeleton_data();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void SpineSkeletonDataResource::update_skeleton_data() {
|
|
if (skeleton_data) {
|
|
delete skeleton_data;
|
|
skeleton_data = nullptr;
|
|
}
|
|
if (animation_state_data) {
|
|
delete animation_state_data;
|
|
animation_state_data = nullptr;
|
|
}
|
|
|
|
emit_signal(SNAME("_internal_spine_objects_invalidated"));
|
|
|
|
if (atlas_res.is_valid() && skeleton_file_res.is_valid()) {
|
|
load_resources(atlas_res->get_spine_atlas(), skeleton_file_res->get_json(),
|
|
skeleton_file_res->get_binary());
|
|
}
|
|
emit_signal(SNAME("skeleton_data_changed"));
|
|
#ifdef TOOLS_ENABLED
|
|
NOTIFY_PROPERTY_LIST_CHANGED();
|
|
#endif
|
|
}
|
|
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
void SpineSkeletonDataResource::load_resources(spine::Atlas *atlas,
|
|
const String &json,
|
|
const PackedByteArray &binary) {
|
|
#else
|
|
void SpineSkeletonDataResource::load_resources(spine::Atlas *atlas,
|
|
const String &json,
|
|
const Vector<uint8_t> &binary) {
|
|
#endif
|
|
if ((EMPTY(json) && EMPTY(binary)) || atlas == nullptr)
|
|
return;
|
|
|
|
spine::SkeletonData *data;
|
|
if (!EMPTY(json)) {
|
|
spine::SkeletonJson skeletonJson(atlas);
|
|
data = skeletonJson.readSkeletonData(json.utf8().ptr());
|
|
if (!data) {
|
|
ERR_PRINT(String("Error while loading skeleton data: ") + get_path());
|
|
ERR_PRINT(String("Error message: ") + skeletonJson.getError().buffer());
|
|
return;
|
|
}
|
|
} else {
|
|
spine::SkeletonBinary skeletonBinary(atlas);
|
|
data = skeletonBinary.readSkeletonData(binary.ptr(), binary.size());
|
|
if (!data) {
|
|
ERR_PRINT(String("Error while loading skeleton data: ") + get_path());
|
|
ERR_PRINT(String("Error message: ") + skeletonBinary.getError().buffer());
|
|
return;
|
|
}
|
|
}
|
|
skeleton_data = data;
|
|
animation_state_data = new spine::AnimationStateData(data);
|
|
update_mixes();
|
|
}
|
|
|
|
bool SpineSkeletonDataResource::is_skeleton_data_loaded() const {
|
|
return skeleton_data != nullptr;
|
|
}
|
|
|
|
void SpineSkeletonDataResource::set_atlas_res(
|
|
const Ref<SpineAtlasResource> &atlas) {
|
|
atlas_res = atlas;
|
|
update_skeleton_data();
|
|
}
|
|
|
|
Ref<SpineAtlasResource> SpineSkeletonDataResource::get_atlas_res() {
|
|
return atlas_res;
|
|
}
|
|
|
|
void SpineSkeletonDataResource::set_skeleton_file_res(
|
|
const Ref<SpineSkeletonFileResource> &skeleton_file) {
|
|
skeleton_file_res = skeleton_file;
|
|
update_skeleton_data();
|
|
}
|
|
|
|
Ref<SpineSkeletonFileResource>
|
|
SpineSkeletonDataResource::get_skeleton_file_res() {
|
|
return skeleton_file_res;
|
|
}
|
|
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
void SpineSkeletonDataResource::get_animation_names(PackedStringArray &animation_names) const {
|
|
#else
|
|
void SpineSkeletonDataResource::get_animation_names(Vector<String> &animation_names) const {
|
|
#endif
|
|
animation_names.clear();
|
|
if (!is_skeleton_data_loaded())
|
|
return;
|
|
auto animations = skeleton_data->getAnimations();
|
|
for (size_t i = 0; i < animations.size(); ++i) {
|
|
auto animation = animations[i];
|
|
String name;
|
|
#if (VERSION_MAJOR >= 4 && VERSION_MINOR >= 5)
|
|
name = String::utf8(animation->getName().buffer());
|
|
#else
|
|
name.parse_utf8(animation->getName().buffer());
|
|
#endif
|
|
animation_names.push_back(name);
|
|
}
|
|
}
|
|
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
void SpineSkeletonDataResource::get_skin_names(PackedStringArray &skin_names) const {
|
|
#else
|
|
void SpineSkeletonDataResource::get_skin_names(Vector<String> &skin_names) const {
|
|
#endif
|
|
skin_names.clear();
|
|
if (!is_skeleton_data_loaded())
|
|
return;
|
|
auto skins = skeleton_data->getSkins();
|
|
for (size_t i = 0; i < skins.size(); ++i) {
|
|
auto skin = skins[i];
|
|
String name;
|
|
#if (VERSION_MAJOR >= 4 && VERSION_MINOR >= 5)
|
|
name = String::utf8(skin->getName().buffer());
|
|
#else
|
|
name.parse_utf8(skin->getName().buffer());
|
|
#endif
|
|
skin_names.push_back(name);
|
|
}
|
|
}
|
|
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
void SpineSkeletonDataResource::get_slot_names(PackedStringArray &slot_names) {
|
|
#else
|
|
void SpineSkeletonDataResource::get_slot_names(Vector<String> &slot_names) {
|
|
#endif
|
|
slot_names.clear();
|
|
if (!is_skeleton_data_loaded())
|
|
return;
|
|
auto slots = skeleton_data->getSlots();
|
|
for (size_t i = 0; i < slots.size(); ++i) {
|
|
auto slot = slots[i];
|
|
String name;
|
|
#if (VERSION_MAJOR >= 4 && VERSION_MINOR >= 5)
|
|
name = String::utf8(slot->getName().buffer());
|
|
#else
|
|
name.parse_utf8(slot->getName().buffer());
|
|
#endif
|
|
slot_names.push_back(name);
|
|
}
|
|
}
|
|
|
|
#ifdef SPINE_GODOT_EXTENSION
|
|
void SpineSkeletonDataResource::get_bone_names(PackedStringArray &bone_names) {
|
|
#else
|
|
void SpineSkeletonDataResource::get_bone_names(Vector<String> &bone_names) {
|
|
#endif
|
|
bone_names.clear();
|
|
if (!is_skeleton_data_loaded())
|
|
return;
|
|
auto bones = skeleton_data->getBones();
|
|
for (size_t i = 0; i < bones.size(); ++i) {
|
|
auto bone = bones[i];
|
|
String name;
|
|
#if (VERSION_MAJOR >= 4 && VERSION_MINOR >= 5)
|
|
name = String::utf8(bone->getName().buffer());
|
|
#else
|
|
name.parse_utf8(bone->getName().buffer());
|
|
#endif
|
|
bone_names.push_back(name);
|
|
}
|
|
}
|
|
|
|
void SpineSkeletonDataResource::set_default_mix(float _default_mix) {
|
|
this->default_mix = _default_mix;
|
|
update_mixes();
|
|
}
|
|
|
|
float SpineSkeletonDataResource::get_default_mix() { return default_mix; }
|
|
|
|
void SpineSkeletonDataResource::set_animation_mixes(Array _animation_mixes) {
|
|
for (int i = 0; i < _animation_mixes.size(); i++) {
|
|
auto objectId = Object::cast_to<EncodedObjectAsID>(_animation_mixes[0]);
|
|
if (objectId) {
|
|
ERR_PRINT("Live-editing of animation mixes is not supported.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
this->animation_mixes = _animation_mixes;
|
|
update_mixes();
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_animation_mixes() {
|
|
return animation_mixes;
|
|
}
|
|
|
|
void SpineSkeletonDataResource::update_mixes() {
|
|
if (!is_skeleton_data_loaded())
|
|
return;
|
|
animation_state_data->clear();
|
|
animation_state_data->setDefaultMix(default_mix);
|
|
for (int i = 0; i < animation_mixes.size(); i++) {
|
|
Ref<SpineAnimationMix> mix = animation_mixes[i];
|
|
spine::Animation *from =
|
|
skeleton_data->findAnimation(mix->get_from().utf8().ptr());
|
|
spine::Animation *to =
|
|
skeleton_data->findAnimation(mix->get_to().utf8().ptr());
|
|
if (!from) {
|
|
ERR_PRINT(vformat("Failed to set animation mix %s->%s. Animation %s does "
|
|
"not exist in skeleton.",
|
|
from, to, from));
|
|
continue;
|
|
}
|
|
if (!to) {
|
|
ERR_PRINT(vformat("Failed to set animation mix %s->%s. Animation %s does "
|
|
"not exist in skeleton.",
|
|
from, to, to));
|
|
continue;
|
|
}
|
|
animation_state_data->setMix(from, to, mix->get_mix());
|
|
}
|
|
}
|
|
|
|
Ref<SpineAnimation>
|
|
SpineSkeletonDataResource::find_animation(const String &animation_name) const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
if (EMPTY(animation_name))
|
|
return nullptr;
|
|
auto animation =
|
|
skeleton_data->findAnimation(SPINE_STRING_TMP(animation_name));
|
|
if (!animation)
|
|
return nullptr;
|
|
Ref<SpineAnimation> animation_ref(memnew(SpineAnimation));
|
|
animation_ref->set_spine_object(this, animation);
|
|
return animation_ref;
|
|
}
|
|
|
|
Ref<SpineBoneData>
|
|
SpineSkeletonDataResource::find_bone(const String &bone_name) const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
if (EMPTY(bone_name))
|
|
return nullptr;
|
|
auto bone = skeleton_data->findBone(SPINE_STRING_TMP(bone_name));
|
|
if (!bone)
|
|
return nullptr;
|
|
Ref<SpineBoneData> bone_ref(memnew(SpineBoneData));
|
|
bone_ref->set_spine_object(this, bone);
|
|
return bone_ref;
|
|
}
|
|
|
|
Ref<SpineSlotData>
|
|
SpineSkeletonDataResource::find_slot(const String &slot_name) const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
if (EMPTY(slot_name))
|
|
return nullptr;
|
|
auto slot = skeleton_data->findSlot(SPINE_STRING_TMP(slot_name));
|
|
if (!slot)
|
|
return nullptr;
|
|
Ref<SpineSlotData> slot_ref(memnew(SpineSlotData));
|
|
slot_ref->set_spine_object(this, slot);
|
|
return slot_ref;
|
|
}
|
|
|
|
Ref<SpineSkin>
|
|
SpineSkeletonDataResource::find_skin(const String &skin_name) const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
if (EMPTY(skin_name))
|
|
return nullptr;
|
|
auto skin = skeleton_data->findSkin(SPINE_STRING_TMP(skin_name));
|
|
if (!skin)
|
|
return nullptr;
|
|
Ref<SpineSkin> skin_ref(memnew(SpineSkin));
|
|
skin_ref->set_spine_object(this, skin);
|
|
return skin_ref;
|
|
}
|
|
|
|
Ref<SpineEventData>
|
|
SpineSkeletonDataResource::find_event(const String &event_data_name) const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
if (EMPTY(event_data_name))
|
|
return nullptr;
|
|
auto event = skeleton_data->findEvent(SPINE_STRING_TMP(event_data_name));
|
|
if (!event)
|
|
return nullptr;
|
|
Ref<SpineEventData> event_ref(memnew(SpineEventData));
|
|
event_ref->set_spine_object(this, event);
|
|
return event_ref;
|
|
}
|
|
|
|
Ref<SpineIkConstraintData> SpineSkeletonDataResource::find_ik_constraint(
|
|
const String &constraint_name) const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
if (EMPTY(constraint_name))
|
|
return nullptr;
|
|
auto constraint =
|
|
skeleton_data->findIkConstraint(SPINE_STRING_TMP(constraint_name));
|
|
if (!constraint)
|
|
return nullptr;
|
|
Ref<SpineIkConstraintData> constraint_ref(memnew(SpineIkConstraintData));
|
|
constraint_ref->set_spine_object(this, constraint);
|
|
return constraint_ref;
|
|
}
|
|
|
|
Ref<SpineTransformConstraintData>
|
|
SpineSkeletonDataResource::find_transform_constraint(
|
|
const String &constraint_name) const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
if (EMPTY(constraint_name))
|
|
return nullptr;
|
|
auto constraint =
|
|
skeleton_data->findTransformConstraint(SPINE_STRING_TMP(constraint_name));
|
|
if (!constraint)
|
|
return nullptr;
|
|
Ref<SpineTransformConstraintData> constraint_ref(
|
|
memnew(SpineTransformConstraintData));
|
|
constraint_ref->set_spine_object(this, constraint);
|
|
return constraint_ref;
|
|
}
|
|
|
|
Ref<SpinePathConstraintData> SpineSkeletonDataResource::find_path_constraint(
|
|
const String &constraint_name) const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
if (EMPTY(constraint_name))
|
|
return nullptr;
|
|
auto constraint =
|
|
skeleton_data->findPathConstraint(SPINE_STRING_TMP(constraint_name));
|
|
if (constraint == nullptr)
|
|
return nullptr;
|
|
Ref<SpinePathConstraintData> constraint_ref(memnew(SpinePathConstraintData));
|
|
constraint_ref->set_spine_object(this, constraint);
|
|
return constraint_ref;
|
|
}
|
|
|
|
Ref<SpinePhysicsConstraintData>
|
|
SpineSkeletonDataResource::find_physics_constraint(
|
|
const String &constraint_name) const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
if (EMPTY(constraint_name))
|
|
return nullptr;
|
|
auto constraint =
|
|
skeleton_data->findPhysicsConstraint(SPINE_STRING_TMP(constraint_name));
|
|
if (constraint == nullptr)
|
|
return nullptr;
|
|
Ref<SpinePhysicsConstraintData> constraint_ref(
|
|
memnew(SpinePhysicsConstraintData));
|
|
constraint_ref->set_spine_object(this, constraint);
|
|
return constraint_ref;
|
|
}
|
|
|
|
String SpineSkeletonDataResource::get_skeleton_name() const {
|
|
SPINE_CHECK(skeleton_data, "")
|
|
String name;
|
|
#if (VERSION_MAJOR >= 4 && VERSION_MINOR >= 5)
|
|
name = String::utf8(skeleton_data->getName().buffer());
|
|
#else
|
|
name.parse_utf8(skeleton_data->getName().buffer());
|
|
#endif
|
|
return name;
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_bones() const {
|
|
Array result;
|
|
SPINE_CHECK(skeleton_data, result)
|
|
auto bones = skeleton_data->getBones();
|
|
result.resize((int) bones.size());
|
|
for (int i = 0; i < bones.size(); ++i) {
|
|
Ref<SpineBoneData> bone_ref(memnew(SpineBoneData));
|
|
bone_ref->set_spine_object(this, bones[i]);
|
|
result[i] = bone_ref;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_slots() const {
|
|
Array result;
|
|
SPINE_CHECK(skeleton_data, result)
|
|
auto slots = skeleton_data->getSlots();
|
|
result.resize((int) slots.size());
|
|
for (int i = 0; i < slots.size(); ++i) {
|
|
Ref<SpineSlotData> slot_ref(memnew(SpineSlotData));
|
|
slot_ref->set_spine_object(this, slots[i]);
|
|
result[i] = slot_ref;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_skins() const {
|
|
Array result;
|
|
SPINE_CHECK(skeleton_data, result)
|
|
auto skins = skeleton_data->getSkins();
|
|
result.resize((int) skins.size());
|
|
for (int i = 0; i < skins.size(); ++i) {
|
|
Ref<SpineSkin> skin_ref(memnew(SpineSkin));
|
|
skin_ref->set_spine_object(this, skins[i]);
|
|
result[i] = skin_ref;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Ref<SpineSkin> SpineSkeletonDataResource::get_default_skin() const {
|
|
SPINE_CHECK(skeleton_data, nullptr)
|
|
auto skin = skeleton_data->getDefaultSkin();
|
|
if (skin)
|
|
return nullptr;
|
|
Ref<SpineSkin> skin_ref(memnew(SpineSkin));
|
|
skin_ref->set_spine_object(this, skin);
|
|
return skin_ref;
|
|
}
|
|
|
|
void SpineSkeletonDataResource::set_default_skin(Ref<SpineSkin> skin) {
|
|
SPINE_CHECK(skeleton_data, )
|
|
skeleton_data->setDefaultSkin(skin.is_valid() && skin->get_spine_object()
|
|
? skin->get_spine_object()
|
|
: nullptr);
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_events() const {
|
|
Array result;
|
|
SPINE_CHECK(skeleton_data, result)
|
|
auto events = skeleton_data->getEvents();
|
|
result.resize((int) events.size());
|
|
for (int i = 0; i < events.size(); ++i) {
|
|
Ref<SpineEventData> event_ref(memnew(SpineEventData));
|
|
event_ref->set_spine_object(this, events[i]);
|
|
result[i] = event_ref;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_animations() const {
|
|
Array result;
|
|
SPINE_CHECK(skeleton_data, result)
|
|
auto animations = skeleton_data->getAnimations();
|
|
result.resize((int) animations.size());
|
|
for (int i = 0; i < animations.size(); ++i) {
|
|
Ref<SpineAnimation> animation_ref(memnew(SpineAnimation));
|
|
animation_ref->set_spine_object(this, animations[i]);
|
|
result[i] = animation_ref;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_ik_constraints() const {
|
|
Array result;
|
|
SPINE_CHECK(skeleton_data, result)
|
|
auto constraints = skeleton_data->getIkConstraints();
|
|
result.resize((int) constraints.size());
|
|
for (int i = 0; i < constraints.size(); ++i) {
|
|
Ref<SpineIkConstraintData> constraint_ref(memnew(SpineIkConstraintData));
|
|
constraint_ref->set_spine_object(this, constraints[i]);
|
|
result[i] = constraint_ref;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_transform_constraints() const {
|
|
Array result;
|
|
SPINE_CHECK(skeleton_data, result)
|
|
auto constraints = skeleton_data->getTransformConstraints();
|
|
result.resize((int) constraints.size());
|
|
for (int i = 0; i < constraints.size(); ++i) {
|
|
Ref<SpineTransformConstraintData> constraint_ref(
|
|
memnew(SpineTransformConstraintData));
|
|
constraint_ref->set_spine_object(this, constraints[i]);
|
|
result[i] = constraint_ref;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_path_constraints() const {
|
|
Array result;
|
|
SPINE_CHECK(skeleton_data, result)
|
|
auto constraints = skeleton_data->getPathConstraints();
|
|
result.resize((int) constraints.size());
|
|
for (int i = 0; i < constraints.size(); ++i) {
|
|
Ref<SpinePathConstraintData> constraint_ref(
|
|
memnew(SpinePathConstraintData));
|
|
constraint_ref->set_spine_object(this, constraints[i]);
|
|
result[i] = constraint_ref;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Array SpineSkeletonDataResource::get_physics_constraints() const {
|
|
Array result;
|
|
SPINE_CHECK(skeleton_data, result)
|
|
auto constraints = skeleton_data->getPhysicsConstraints();
|
|
result.resize((int) constraints.size());
|
|
for (int i = 0; i < constraints.size(); ++i) {
|
|
Ref<SpinePhysicsConstraintData> constraint_ref(
|
|
memnew(SpinePhysicsConstraintData));
|
|
constraint_ref->set_spine_object(this, constraints[i]);
|
|
result[i] = constraint_ref;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
float SpineSkeletonDataResource::get_x() const {
|
|
SPINE_CHECK(skeleton_data, 0)
|
|
return skeleton_data->getX();
|
|
}
|
|
|
|
float SpineSkeletonDataResource::get_y() const {
|
|
SPINE_CHECK(skeleton_data, 0)
|
|
return skeleton_data->getY();
|
|
}
|
|
|
|
float SpineSkeletonDataResource::get_width() const {
|
|
SPINE_CHECK(skeleton_data, 0)
|
|
return skeleton_data->getWidth();
|
|
}
|
|
|
|
float SpineSkeletonDataResource::get_height() const {
|
|
SPINE_CHECK(skeleton_data, 0)
|
|
return skeleton_data->getHeight();
|
|
}
|
|
|
|
String SpineSkeletonDataResource::get_version() const {
|
|
SPINE_CHECK(skeleton_data, "")
|
|
return skeleton_data->getVersion().buffer();
|
|
}
|
|
|
|
String SpineSkeletonDataResource::get_hash() const {
|
|
SPINE_CHECK(skeleton_data, "")
|
|
return skeleton_data->getHash().buffer();
|
|
}
|
|
|
|
String SpineSkeletonDataResource::get_images_path() const {
|
|
SPINE_CHECK(skeleton_data, "")
|
|
return skeleton_data->getImagesPath().buffer();
|
|
}
|
|
|
|
String SpineSkeletonDataResource::get_audio_path() const {
|
|
SPINE_CHECK(skeleton_data, "")
|
|
return skeleton_data->getAudioPath().buffer();
|
|
}
|
|
|
|
float SpineSkeletonDataResource::get_fps() const {
|
|
SPINE_CHECK(skeleton_data, 0)
|
|
return skeleton_data->getFps();
|
|
}
|
|
|
|
float SpineSkeletonDataResource::get_reference_scale() const {
|
|
SPINE_CHECK(skeleton_data, 100);
|
|
return skeleton_data->getReferenceScale();
|
|
}
|
|
|
|
void SpineSkeletonDataResource::set_reference_scale(float reference_scale) {
|
|
SPINE_CHECK(skeleton_data, )
|
|
skeleton_data->setReferenceScale(reference_scale);
|
|
}
|