diff options
-rw-r--r-- | scene/2d/animated_sprite_2d.cpp | 208 | ||||
-rw-r--r-- | scene/2d/animated_sprite_2d.h | 67 | ||||
-rw-r--r-- | scene/3d/sprite_3d.h | 2 | ||||
-rw-r--r-- | scene/resources/sprite_frames.cpp | 241 | ||||
-rw-r--r-- | scene/resources/sprite_frames.h | 102 |
5 files changed, 345 insertions, 275 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index f39850441b..359044a576 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -105,214 +105,6 @@ Rect2 AnimatedSprite2D::_get_rect() const { return Rect2(ofs, s); } -void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) { - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - - if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) { - E->get().frames.insert(p_at_pos, p_frame); - } else { - E->get().frames.push_back(p_frame); - } - - emit_changed(); -} - -int SpriteFrames::get_frame_count(const StringName &p_anim) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); - - return E->get().frames.size(); -} - -void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) { - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - - E->get().frames.remove(p_idx); - emit_changed(); -} - -void SpriteFrames::clear(const StringName &p_anim) { - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - - E->get().frames.clear(); - emit_changed(); -} - -void SpriteFrames::clear_all() { - animations.clear(); - add_animation("default"); -} - -void SpriteFrames::add_animation(const StringName &p_anim) { - ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'."); - - animations[p_anim] = Anim(); -} - -bool SpriteFrames::has_animation(const StringName &p_anim) const { - return animations.has(p_anim); -} - -void SpriteFrames::remove_animation(const StringName &p_anim) { - animations.erase(p_anim); -} - -void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) { - ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'."); - ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists."); - - Anim anim = animations[p_prev]; - animations.erase(p_prev); - animations[p_next] = anim; -} - -Vector<String> SpriteFrames::_get_animation_list() const { - Vector<String> ret; - List<StringName> al; - get_animation_list(&al); - for (List<StringName>::Element *E = al.front(); E; E = E->next()) { - ret.push_back(E->get()); - } - - return ret; -} - -void SpriteFrames::get_animation_list(List<StringName> *r_animations) const { - for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { - r_animations->push_back(E->key()); - } -} - -Vector<String> SpriteFrames::get_animation_names() const { - Vector<String> names; - for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { - names.push_back(E->key()); - } - names.sort(); - return names; -} - -void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) { - ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ")."); - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - E->get().speed = p_fps; -} - -float SpriteFrames::get_animation_speed(const StringName &p_anim) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); - return E->get().speed; -} - -void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) { - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - E->get().loop = p_loop; -} - -bool SpriteFrames::get_animation_loop(const StringName &p_anim) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist."); - return E->get().loop; -} - -void SpriteFrames::_set_frames(const Array &p_frames) { - clear_all(); - Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default); - ERR_FAIL_COND(!E); - - E->get().frames.resize(p_frames.size()); - for (int i = 0; i < E->get().frames.size(); i++) { - E->get().frames.write[i] = p_frames[i]; - } -} - -Array SpriteFrames::_get_frames() const { - return Array(); -} - -Array SpriteFrames::_get_animations() const { - Array anims; - for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { - Dictionary d; - d["name"] = E->key(); - d["speed"] = E->get().speed; - d["loop"] = E->get().loop; - Array frames; - for (int i = 0; i < E->get().frames.size(); i++) { - frames.push_back(E->get().frames[i]); - } - d["frames"] = frames; - anims.push_back(d); - } - - return anims; -} - -void SpriteFrames::_set_animations(const Array &p_animations) { - animations.clear(); - for (int i = 0; i < p_animations.size(); i++) { - Dictionary d = p_animations[i]; - - ERR_CONTINUE(!d.has("name")); - ERR_CONTINUE(!d.has("speed")); - ERR_CONTINUE(!d.has("loop")); - ERR_CONTINUE(!d.has("frames")); - - Anim anim; - anim.speed = d["speed"]; - anim.loop = d["loop"]; - Array frames = d["frames"]; - for (int j = 0; j < frames.size(); j++) { - RES res = frames[j]; - anim.frames.push_back(res); - } - - animations[d["name"]] = anim; - } -} - -void SpriteFrames::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation); - ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation); - ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation); - ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation); - - ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names); - - ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed); - ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed); - - ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop); - ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop); - - ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count); - ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame); - ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame); - ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame); - ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear); - ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all); - - ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames); - ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames); - - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility - - ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations); - ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations); - - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility -} - -SpriteFrames::SpriteFrames() { - add_animation(SceneStringNames::get_singleton()->_default); -} - void AnimatedSprite2D::_validate_property(PropertyInfo &property) const { if (!frames.is_valid()) { return; diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h index 5e53a401e2..14ecb18866 100644 --- a/scene/2d/animated_sprite_2d.h +++ b/scene/2d/animated_sprite_2d.h @@ -32,74 +32,9 @@ #define ANIMATED_SPRITE_2D_H #include "scene/2d/node_2d.h" +#include "scene/resources/sprite_frames.h" #include "scene/resources/texture.h" -class SpriteFrames : public Resource { - GDCLASS(SpriteFrames, Resource); - - struct Anim { - float speed = 5.0; - bool loop = true; - Vector<Ref<Texture2D>> frames; - }; - - Map<StringName, Anim> animations; - - Array _get_frames() const; - void _set_frames(const Array &p_frames); - - Array _get_animations() const; - void _set_animations(const Array &p_animations); - - Vector<String> _get_animation_list() const; - -protected: - static void _bind_methods(); - -public: - void add_animation(const StringName &p_anim); - bool has_animation(const StringName &p_anim) const; - void remove_animation(const StringName &p_anim); - void rename_animation(const StringName &p_prev, const StringName &p_next); - - void get_animation_list(List<StringName> *r_animations) const; - Vector<String> get_animation_names() const; - - void set_animation_speed(const StringName &p_anim, float p_fps); - float get_animation_speed(const StringName &p_anim) const; - - void set_animation_loop(const StringName &p_anim, bool p_loop); - bool get_animation_loop(const StringName &p_anim) const; - - void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1); - int get_frame_count(const StringName &p_anim) const; - _FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist."); - ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>()); - if (p_idx >= E->get().frames.size()) { - return Ref<Texture2D>(); - } - - return E->get().frames[p_idx]; - } - - void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) { - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - ERR_FAIL_COND(p_idx < 0); - if (p_idx >= E->get().frames.size()) { - return; - } - E->get().frames.write[p_idx] = p_frame; - } - void remove_frame(const StringName &p_anim, int p_idx); - void clear(const StringName &p_anim); - void clear_all(); - - SpriteFrames(); -}; - class AnimatedSprite2D : public Node2D { GDCLASS(AnimatedSprite2D, Node2D); diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index a9ce2d8eee..e46a53da0d 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -31,8 +31,8 @@ #ifndef SPRITE_3D_H #define SPRITE_3D_H -#include "scene/2d/animated_sprite_2d.h" #include "scene/3d/visual_instance_3d.h" +#include "scene/resources/sprite_frames.h" class SpriteBase3D : public GeometryInstance3D { GDCLASS(SpriteBase3D, GeometryInstance3D); diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp new file mode 100644 index 0000000000..90c702081b --- /dev/null +++ b/scene/resources/sprite_frames.cpp @@ -0,0 +1,241 @@ +/*************************************************************************/ +/* sprite_frames.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "sprite_frames.h" + +#include "scene/scene_string_names.h" + +void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) { + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + + if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) { + E->get().frames.insert(p_at_pos, p_frame); + } else { + E->get().frames.push_back(p_frame); + } + + emit_changed(); +} + +int SpriteFrames::get_frame_count(const StringName &p_anim) const { + const Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); + + return E->get().frames.size(); +} + +void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) { + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + + E->get().frames.remove(p_idx); + emit_changed(); +} + +void SpriteFrames::clear(const StringName &p_anim) { + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + + E->get().frames.clear(); + emit_changed(); +} + +void SpriteFrames::clear_all() { + animations.clear(); + add_animation("default"); +} + +void SpriteFrames::add_animation(const StringName &p_anim) { + ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'."); + + animations[p_anim] = Anim(); +} + +bool SpriteFrames::has_animation(const StringName &p_anim) const { + return animations.has(p_anim); +} + +void SpriteFrames::remove_animation(const StringName &p_anim) { + animations.erase(p_anim); +} + +void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) { + ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'."); + ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists."); + + Anim anim = animations[p_prev]; + animations.erase(p_prev); + animations[p_next] = anim; +} + +Vector<String> SpriteFrames::_get_animation_list() const { + Vector<String> ret; + List<StringName> al; + get_animation_list(&al); + for (List<StringName>::Element *E = al.front(); E; E = E->next()) { + ret.push_back(E->get()); + } + + return ret; +} + +void SpriteFrames::get_animation_list(List<StringName> *r_animations) const { + for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { + r_animations->push_back(E->key()); + } +} + +Vector<String> SpriteFrames::get_animation_names() const { + Vector<String> names; + for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { + names.push_back(E->key()); + } + names.sort(); + return names; +} + +void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) { + ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ")."); + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + E->get().speed = p_fps; +} + +float SpriteFrames::get_animation_speed(const StringName &p_anim) const { + const Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); + return E->get().speed; +} + +void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) { + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + E->get().loop = p_loop; +} + +bool SpriteFrames::get_animation_loop(const StringName &p_anim) const { + const Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist."); + return E->get().loop; +} + +void SpriteFrames::_set_frames(const Array &p_frames) { + clear_all(); + Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default); + ERR_FAIL_COND(!E); + + E->get().frames.resize(p_frames.size()); + for (int i = 0; i < E->get().frames.size(); i++) { + E->get().frames.write[i] = p_frames[i]; + } +} + +Array SpriteFrames::_get_frames() const { + return Array(); +} + +Array SpriteFrames::_get_animations() const { + Array anims; + for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { + Dictionary d; + d["name"] = E->key(); + d["speed"] = E->get().speed; + d["loop"] = E->get().loop; + Array frames; + for (int i = 0; i < E->get().frames.size(); i++) { + frames.push_back(E->get().frames[i]); + } + d["frames"] = frames; + anims.push_back(d); + } + + return anims; +} + +void SpriteFrames::_set_animations(const Array &p_animations) { + animations.clear(); + for (int i = 0; i < p_animations.size(); i++) { + Dictionary d = p_animations[i]; + + ERR_CONTINUE(!d.has("name")); + ERR_CONTINUE(!d.has("speed")); + ERR_CONTINUE(!d.has("loop")); + ERR_CONTINUE(!d.has("frames")); + + Anim anim; + anim.speed = d["speed"]; + anim.loop = d["loop"]; + Array frames = d["frames"]; + for (int j = 0; j < frames.size(); j++) { + RES res = frames[j]; + anim.frames.push_back(res); + } + + animations[d["name"]] = anim; + } +} + +void SpriteFrames::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation); + ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation); + ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation); + ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation); + + ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names); + + ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed); + ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed); + + ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop); + ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop); + + ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count); + ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame); + ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame); + ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame); + ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear); + ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all); + + ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames); + ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames); + + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility + + ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations); + ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations); + + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility +} + +SpriteFrames::SpriteFrames() { + add_animation(SceneStringNames::get_singleton()->_default); +} diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h new file mode 100644 index 0000000000..282c5f20ab --- /dev/null +++ b/scene/resources/sprite_frames.h @@ -0,0 +1,102 @@ +/*************************************************************************/ +/* sprite_frames.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SPRITE_FRAMES_H +#define SPRITE_FRAMES_H + +#include "scene/resources/texture.h" + +class SpriteFrames : public Resource { + GDCLASS(SpriteFrames, Resource); + + struct Anim { + float speed = 5.0; + bool loop = true; + Vector<Ref<Texture2D>> frames; + }; + + Map<StringName, Anim> animations; + + Array _get_frames() const; + void _set_frames(const Array &p_frames); + + Array _get_animations() const; + void _set_animations(const Array &p_animations); + + Vector<String> _get_animation_list() const; + +protected: + static void _bind_methods(); + +public: + void add_animation(const StringName &p_anim); + bool has_animation(const StringName &p_anim) const; + void remove_animation(const StringName &p_anim); + void rename_animation(const StringName &p_prev, const StringName &p_next); + + void get_animation_list(List<StringName> *r_animations) const; + Vector<String> get_animation_names() const; + + void set_animation_speed(const StringName &p_anim, float p_fps); + float get_animation_speed(const StringName &p_anim) const; + + void set_animation_loop(const StringName &p_anim, bool p_loop); + bool get_animation_loop(const StringName &p_anim) const; + + void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1); + int get_frame_count(const StringName &p_anim) const; + _FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const { + const Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist."); + ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>()); + if (p_idx >= E->get().frames.size()) { + return Ref<Texture2D>(); + } + + return E->get().frames[p_idx]; + } + + void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) { + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + ERR_FAIL_COND(p_idx < 0); + if (p_idx >= E->get().frames.size()) { + return; + } + E->get().frames.write[p_idx] = p_frame; + } + void remove_frame(const StringName &p_anim, int p_idx); + void clear(const StringName &p_anim); + void clear_all(); + + SpriteFrames(); +}; + +#endif // SPRITE_FRAMES_H |