/****************************************************************************** * Spine Runtimes License Agreement * Last updated January 1, 2020. Replaces all prior versions. * * Copyright (c) 2013-2020, 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" void SpineSkeletonDataResource::_bind_methods() { 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_json_res", "skeleton_json_res"), &SpineSkeletonDataResource::set_skeleton_json_res); ClassDB::bind_method(D_METHOD("get_skeleton_json_res"), &SpineSkeletonDataResource::get_skeleton_json_res); ClassDB::bind_method(D_METHOD("is_skeleton_data_loaded"), &SpineSkeletonDataResource::is_skeleton_data_loaded); ClassDB::bind_method(D_METHOD("find_animation", "animation_name"), &SpineSkeletonDataResource::find_animation); ClassDB::bind_method(D_METHOD("get_sk_name"), &SpineSkeletonDataResource::get_sk_name); ClassDB::bind_method(D_METHOD("set_sk_name", "sk_name"), &SpineSkeletonDataResource::set_sk_name); ClassDB::bind_method(D_METHOD("get_x"), &SpineSkeletonDataResource::get_x); ClassDB::bind_method(D_METHOD("set_x", "v"), &SpineSkeletonDataResource::set_x); ClassDB::bind_method(D_METHOD("get_y"), &SpineSkeletonDataResource::get_y); ClassDB::bind_method(D_METHOD("set_y", "v"), &SpineSkeletonDataResource::set_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_fps"), &SpineSkeletonDataResource::get_fps); ClassDB::bind_method(D_METHOD("set_fps", "v"), &SpineSkeletonDataResource::set_fps); 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_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("get_all_bone_data"), &SpineSkeletonDataResource::get_bones); ClassDB::bind_method(D_METHOD("get_all_slot_data"), &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", "v"), &SpineSkeletonDataResource::set_default_skin); ClassDB::bind_method(D_METHOD("get_all_event_data"), &SpineSkeletonDataResource::get_events); ClassDB::bind_method(D_METHOD("get_animations"), &SpineSkeletonDataResource::get_animations); ClassDB::bind_method(D_METHOD("get_all_ik_constraint_data"), &SpineSkeletonDataResource::get_ik_constraints); ClassDB::bind_method(D_METHOD("get_all_transform_constraint_data"), &SpineSkeletonDataResource::get_transform_constraints); ClassDB::bind_method(D_METHOD("get_all_path_constraint_data"), &SpineSkeletonDataResource::get_path_constraints); ADD_SIGNAL(MethodInfo("skeleton_data_loaded")); ADD_SIGNAL(MethodInfo("atlas_res_changed")); ADD_SIGNAL(MethodInfo("skeleton_json_res_changed")); 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_json_res", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE, "SpineSkeletonJsonDataResource"), "set_skeleton_json_res", "get_skeleton_json_res"); } SpineSkeletonDataResource::SpineSkeletonDataResource() : valid(false), spine_object(false), skeleton_data(NULL) { } SpineSkeletonDataResource::~SpineSkeletonDataResource() { if (skeleton_data && !spine_object) { delete skeleton_data; skeleton_data = NULL; } } bool SpineSkeletonDataResource::is_skeleton_data_loaded() const { return valid || spine_object; } void SpineSkeletonDataResource::load_res(spine::Atlas *a, const String &json_string) { if (json_string.empty()) return; auto path = get_path(); spine::SkeletonJson json(a); auto temp_skeleton_data = json.readSkeletonData(json_string.utf8()); if (!temp_skeleton_data) { print_error(String("Error happened while loading skeleton json data: ") + path); print_error(String("Error msg: ") + json.getError().buffer()); return; } if (skeleton_data) { delete skeleton_data; skeleton_data = NULL; } skeleton_data = temp_skeleton_data; valid = true; // print_line("Skeleton json data loaded!"); } void SpineSkeletonDataResource::update_skeleton_data() { if (atlas_res.is_valid() && skeleton_json_res.is_valid()) { load_res(atlas_res->get_spine_atlas(), skeleton_json_res->get_json_string()); if (valid) { emit_signal("skeleton_data_loaded"); } } } void SpineSkeletonDataResource::set_atlas_res(const Ref &a) { atlas_res = a; valid = false; emit_signal("atlas_res_changed"); update_skeleton_data(); } Ref SpineSkeletonDataResource::get_atlas_res() { if (spine_object) { print_line("Getting atlas res from a spine_object skeleton! The result may be NULL!"); } return atlas_res; } void SpineSkeletonDataResource::set_skeleton_json_res(const Ref &s) { skeleton_json_res = s; valid = false; // print_line("skeleton_json_res_changed emitted"); emit_signal("skeleton_json_res_changed"); update_skeleton_data(); } Ref SpineSkeletonDataResource::get_skeleton_json_res() { if (spine_object) { print_line("Getting atlas res from a spine_object skeleton! The result may be NULL!"); } return skeleton_json_res; } #define CHECK_V \ if (!is_skeleton_data_loaded()) { \ ERR_PRINT("skeleton data has not loaded yet!"); \ return; \ } #define CHECK_X(x) \ if (!is_skeleton_data_loaded()) { \ ERR_PRINT("skeleton data has not loaded yet!"); \ return x; \ } #define S_T(x) (spine::String(x.utf8())) Ref SpineSkeletonDataResource::find_animation(const String &animation_name) { CHECK_X(NULL); if (animation_name.empty()) { return NULL; } auto a = skeleton_data->findAnimation(S_T(animation_name)); if (!a) return NULL; Ref sa(memnew(SpineAnimation)); sa->set_spine_object(a); return sa; } String SpineSkeletonDataResource::get_sk_name() { CHECK_X("error"); return skeleton_data->getName().buffer(); } void SpineSkeletonDataResource::set_sk_name(const String &v) { CHECK_V; skeleton_data->setName(S_T(v)); } float SpineSkeletonDataResource::get_x() { CHECK_X(0); return skeleton_data->getX(); } void SpineSkeletonDataResource::set_x(float v) { CHECK_V; skeleton_data->setX(v); } float SpineSkeletonDataResource::get_y() { CHECK_X(0); return skeleton_data->getY(); } void SpineSkeletonDataResource::set_y(float v) { CHECK_V; skeleton_data->setY(v); } float SpineSkeletonDataResource::get_width() { CHECK_X(0); return skeleton_data->getWidth(); } float SpineSkeletonDataResource::get_height() { CHECK_X(0); return skeleton_data->getHeight(); } String SpineSkeletonDataResource::get_version() { CHECK_X("error"); return skeleton_data->getVersion().buffer(); } float SpineSkeletonDataResource::get_fps() { CHECK_X(0); return skeleton_data->getFps(); } void SpineSkeletonDataResource::set_fps(float v) { CHECK_V; skeleton_data->setFps(v); } Ref SpineSkeletonDataResource::find_bone(const String &bone_name) { if (bone_name.empty()) return NULL; auto b = skeleton_data->findBone(S_T(bone_name)); if (b == NULL) return NULL; Ref gd_b(memnew(SpineBoneData)); gd_b->set_spine_object(b); return gd_b; } Ref SpineSkeletonDataResource::find_slot(const String &slot_name) { if (slot_name.empty()) return NULL; auto b = skeleton_data->findSlot(S_T(slot_name)); if (b == NULL) return NULL; Ref gd_b(memnew(SpineSlotData)); gd_b->set_spine_object(b); return gd_b; } Ref SpineSkeletonDataResource::find_skin(const String &skin_name) { if (skin_name.empty()) return NULL; auto b = skeleton_data->findSkin(S_T(skin_name)); if (b == NULL) return NULL; Ref gd_b(memnew(SpineSkin)); gd_b->set_spine_object(b); return gd_b; } Ref SpineSkeletonDataResource::find_event(const String &event_data_name) { if (event_data_name.empty()) return NULL; auto b = skeleton_data->findEvent(S_T(event_data_name)); if (b == NULL) return NULL; Ref gd_b(memnew(SpineEventData)); gd_b->set_spine_object(b); return gd_b; } Ref SpineSkeletonDataResource::find_ik_constraint(const String &constraint_name) { if (constraint_name.empty()) return NULL; auto b = skeleton_data->findIkConstraint(S_T(constraint_name)); if (b == NULL) return NULL; Ref gd_b(memnew(SpineIkConstraintData)); gd_b->set_spine_object(b); return gd_b; } Ref SpineSkeletonDataResource::find_transform_constraint(const String &constraint_name) { if (constraint_name.empty()) return NULL; auto b = skeleton_data->findTransformConstraint(S_T(constraint_name)); if (b == NULL) return NULL; Ref gd_b(memnew(SpineTransformConstraintData)); gd_b->set_spine_object(b); return gd_b; } Ref SpineSkeletonDataResource::find_path_constraint(const String &constraint_name) { if (constraint_name.empty()) return NULL; auto b = skeleton_data->findPathConstraint(S_T(constraint_name)); if (b == NULL) return NULL; Ref gd_b(memnew(SpinePathConstraintData)); gd_b->set_spine_object(b); return gd_b; } Array SpineSkeletonDataResource::get_bones() { auto bs = skeleton_data->getBones(); Array gd_bs; gd_bs.resize(bs.size()); for (size_t i = 0; i < bs.size(); ++i) { if (bs[i] == NULL) gd_bs[i] = Ref(NULL); else { Ref gd_b(memnew(SpineBoneData)); gd_b->set_spine_object(bs[i]); gd_bs[i] = gd_b; } } return gd_bs; } Array SpineSkeletonDataResource::get_slots() { auto bs = skeleton_data->getSlots(); Array gd_bs; gd_bs.resize(bs.size()); for (size_t i = 0; i < bs.size(); ++i) { if (bs[i] == NULL) gd_bs[i] = Ref(NULL); else { Ref gd_b(memnew(SpineSlotData)); gd_b->set_spine_object(bs[i]); gd_bs[i] = gd_b; } } return gd_bs; } Array SpineSkeletonDataResource::get_skins() const { auto bs = skeleton_data->getSkins(); Array gd_bs; gd_bs.resize(bs.size()); for (size_t i = 0; i < bs.size(); ++i) { if (bs[i] == NULL) gd_bs[i] = Ref(NULL); else { Ref gd_b(memnew(SpineSkin)); gd_b->set_spine_object(bs[i]); gd_bs[i] = gd_b; } } return gd_bs; } Ref SpineSkeletonDataResource::get_default_skin() { auto b = skeleton_data->getDefaultSkin(); if (b == NULL) return NULL; Ref gd_b(memnew(SpineSkin)); gd_b->set_spine_object(b); return gd_b; } void SpineSkeletonDataResource::set_default_skin(Ref v) { if (v.is_valid()) { skeleton_data->setDefaultSkin(v->get_spine_object()); } else skeleton_data->setDefaultSkin(NULL); } Array SpineSkeletonDataResource::get_events() { auto bs = skeleton_data->getEvents(); Array gd_bs; gd_bs.resize(bs.size()); for (size_t i = 0; i < bs.size(); ++i) { if (bs[i] == NULL) gd_bs[i] = Ref(NULL); else { Ref gd_b(memnew(SpineEventData)); gd_b->set_spine_object(bs[i]); gd_bs[i] = gd_b; } } return gd_bs; } Array SpineSkeletonDataResource::get_animations() { auto bs = skeleton_data->getAnimations(); Array gd_bs; gd_bs.resize(bs.size()); for (size_t i = 0; i < bs.size(); ++i) { if (bs[i] == NULL) gd_bs[i] = Ref(NULL); else { Ref gd_b(memnew(SpineAnimation)); gd_b->set_spine_object(bs[i]); gd_bs[i] = gd_b; } } return gd_bs; } Array SpineSkeletonDataResource::get_ik_constraints() { auto bs = skeleton_data->getIkConstraints(); Array gd_bs; gd_bs.resize(bs.size()); for (size_t i = 0; i < bs.size(); ++i) { if (bs[i] == NULL) gd_bs[i] = Ref(NULL); else { Ref gd_b(memnew(SpineIkConstraintData)); gd_b->set_spine_object(bs[i]); gd_bs[i] = gd_b; } } return gd_bs; } Array SpineSkeletonDataResource::get_transform_constraints() { auto bs = skeleton_data->getTransformConstraints(); Array gd_bs; gd_bs.resize(bs.size()); for (size_t i = 0; i < bs.size(); ++i) { if (bs[i] == NULL) gd_bs[i] = Ref(NULL); else { Ref gd_b(memnew(SpineTransformConstraintData)); gd_b->set_spine_object(bs[i]); gd_bs[i] = gd_b; } } return gd_bs; } Array SpineSkeletonDataResource::get_path_constraints() { auto bs = skeleton_data->getPathConstraints(); Array gd_bs; gd_bs.resize(bs.size()); for (size_t i = 0; i < bs.size(); ++i) { if (bs[i] == NULL) gd_bs[i] = Ref(NULL); else { Ref gd_b(memnew(SpinePathConstraintData)); gd_b->set_spine_object(bs[i]); gd_bs[i] = gd_b; } } return gd_bs; } #undef S_T #undef CHECK_V #undef CHECK_X //External feature functions void SpineSkeletonDataResource::get_animation_names(Vector &res) const { res.clear(); if (!is_skeleton_data_loaded()) { return; } auto as = skeleton_data->getAnimations(); for (size_t i = 0; i < as.size(); ++i) { auto a = as[i]; if (a) { res.push_back(a->getName().buffer()); } else { res.push_back(""); } } } void SpineSkeletonDataResource::get_skin_names(Vector &res) const { res.clear(); if (!is_skeleton_data_loaded()) { return; } auto as = get_skins(); res.resize(as.size()); for (size_t i = 0; i < as.size(); ++i) { auto a = Ref(as[i]); if (a.is_valid()) { res.push_back(a->get_skin_name()); } else { res.push_back(""); } } } void SpineSkeletonDataResource::_get_property_list(List *p_list) const { PropertyInfo p; Vector res; p.name = "animations"; p.type = Variant::STRING; get_animation_names(res); p.hint_string = String(",").join(res); p.hint = PROPERTY_HINT_ENUM; p_list->push_back(p); p.name = "skins"; p.type = Variant::STRING; get_skin_names(res); p.hint_string = String(",").join(res); p.hint = PROPERTY_HINT_ENUM; p_list->push_back(p); }