From eaae4b6408361eb34363adcb22a08046f43147f4 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 26 Mar 2020 18:49:16 -0300 Subject: Renamed 2D and 3D nodes to make their types explicit Fixes #30736. --- scene/2d/animated_sprite.cpp | 772 ------------------------------------ scene/2d/animated_sprite.h | 231 ----------- scene/2d/animated_sprite_2d.cpp | 772 ++++++++++++++++++++++++++++++++++++ scene/2d/animated_sprite_2d.h | 231 +++++++++++ scene/2d/sprite.cpp | 539 ------------------------- scene/2d/sprite.h | 143 ------- scene/2d/sprite_2d.cpp | 539 +++++++++++++++++++++++++ scene/2d/sprite_2d.h | 143 +++++++ scene/2d/visibility_notifier_2d.cpp | 6 +- 9 files changed, 1688 insertions(+), 1688 deletions(-) delete mode 100644 scene/2d/animated_sprite.cpp delete mode 100644 scene/2d/animated_sprite.h create mode 100644 scene/2d/animated_sprite_2d.cpp create mode 100644 scene/2d/animated_sprite_2d.h delete mode 100644 scene/2d/sprite.cpp delete mode 100644 scene/2d/sprite.h create mode 100644 scene/2d/sprite_2d.cpp create mode 100644 scene/2d/sprite_2d.h (limited to 'scene/2d') diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp deleted file mode 100644 index f3f7ba9ddd..0000000000 --- a/scene/2d/animated_sprite.cpp +++ /dev/null @@ -1,772 +0,0 @@ -/*************************************************************************/ -/* animated_sprite.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 "animated_sprite.h" - -#include "core/os/os.h" -#include "scene/scene_string_names.h" - -#define NORMAL_SUFFIX "_normal" -#define SPECULAR_SUFFIX "_specular" - -#ifdef TOOLS_ENABLED -Dictionary AnimatedSprite::_edit_get_state() const { - Dictionary state = Node2D::_edit_get_state(); - state["offset"] = offset; - return state; -} - -void AnimatedSprite::_edit_set_state(const Dictionary &p_state) { - Node2D::_edit_set_state(p_state); - set_offset(p_state["offset"]); -} - -void AnimatedSprite::_edit_set_pivot(const Point2 &p_pivot) { - set_offset(get_offset() - p_pivot); - set_position(get_transform().xform(p_pivot)); -} - -Point2 AnimatedSprite::_edit_get_pivot() const { - return Vector2(); -} - -bool AnimatedSprite::_edit_use_pivot() const { - return true; -} - -Rect2 AnimatedSprite::_edit_get_rect() const { - return _get_rect(); -} - -bool AnimatedSprite::_edit_use_rect() const { - if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) { - return false; - } - Ref t; - if (animation) - t = frames->get_frame(animation, frame); - return t.is_valid(); -} -#endif - -Rect2 AnimatedSprite::get_anchorable_rect() const { - return _get_rect(); -} - -Rect2 AnimatedSprite::_get_rect() const { - if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) { - return Rect2(); - } - - Ref t; - if (animation) - t = frames->get_frame(animation, frame); - if (t.is_null()) - return Rect2(); - Size2 s = t->get_size(); - - Point2 ofs = offset; - if (centered) - ofs -= Size2(s) / 2; - - if (s == Size2(0, 0)) - s = Size2(1, 1); - - return Rect2(ofs, s); -} - -void SpriteFrames::add_frame(const StringName &p_anim, const Ref &p_frame, int p_at_pos) { - - Map::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::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::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::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(); - animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX; - animations[p_anim].specular_name = String(p_anim) + SPECULAR_SUFFIX; -} - -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; - animations[p_next].normal_name = String(p_next) + NORMAL_SUFFIX; - animations[p_next].specular_name = String(p_next) + SPECULAR_SUFFIX; -} - -Vector SpriteFrames::_get_animation_list() const { - - Vector ret; - List al; - get_animation_list(&al); - for (List::Element *E = al.front(); E; E = E->next()) { - - ret.push_back(E->get()); - } - - return ret; -} - -void SpriteFrames::get_animation_list(List *r_animations) const { - - for (const Map::Element *E = animations.front(); E; E = E->next()) { - r_animations->push_back(E->key()); - } -} - -Vector SpriteFrames::get_animation_names() const { - - Vector names; - for (const Map::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::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::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::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::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::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::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 AnimatedSprite::_validate_property(PropertyInfo &property) const { - - if (!frames.is_valid()) - return; - if (property.name == "animation") { - - property.hint = PROPERTY_HINT_ENUM; - List names; - frames->get_animation_list(&names); - names.sort_custom(); - - bool current_found = false; - - for (List::Element *E = names.front(); E; E = E->next()) { - if (E->prev()) { - property.hint_string += ","; - } - - property.hint_string += String(E->get()); - if (animation == E->get()) { - current_found = true; - } - } - - if (!current_found) { - if (property.hint_string == String()) { - property.hint_string = String(animation); - } else { - property.hint_string = String(animation) + "," + property.hint_string; - } - } - } - - if (property.name == "frame") { - property.hint = PROPERTY_HINT_RANGE; - if (frames->has_animation(animation) && frames->get_frame_count(animation) > 1) { - property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; - } - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; - } -} - -void AnimatedSprite::_notification(int p_what) { - - switch (p_what) { - case NOTIFICATION_INTERNAL_PROCESS: { - - if (frames.is_null()) - return; - if (!frames->has_animation(animation)) - return; - if (frame < 0) - return; - - float speed = frames->get_animation_speed(animation) * speed_scale; - if (speed == 0) - return; //do nothing - - float remaining = get_process_delta_time(); - - while (remaining) { - - if (timeout <= 0) { - - timeout = _get_frame_duration(); - - int fc = frames->get_frame_count(animation); - if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) { - if (frames->get_animation_loop(animation)) { - if (backwards) - frame = fc - 1; - else - frame = 0; - - emit_signal(SceneStringNames::get_singleton()->animation_finished); - } else { - if (backwards) - frame = 0; - else - frame = fc - 1; - - if (!is_over) { - is_over = true; - emit_signal(SceneStringNames::get_singleton()->animation_finished); - } - } - } else { - if (backwards) - frame--; - else - frame++; - } - - update(); - _change_notify("frame"); - emit_signal(SceneStringNames::get_singleton()->frame_changed); - } - - float to_process = MIN(timeout, remaining); - remaining -= to_process; - timeout -= to_process; - } - } break; - - case NOTIFICATION_DRAW: { - - if (frames.is_null()) - return; - if (frame < 0) - return; - if (!frames->has_animation(animation)) - return; - - Ref texture = frames->get_frame(animation, frame); - if (texture.is_null()) - return; - - Ref normal = frames->get_normal_frame(animation, frame); - Ref specular = frames->get_specular_frame(animation, frame); - - RID ci = get_canvas_item(); - - Size2i s; - s = texture->get_size(); - Point2 ofs = offset; - if (centered) - ofs -= s / 2; - - if (Engine::get_singleton()->get_use_pixel_snap()) { - ofs = ofs.floor(); - } - Rect2 dst_rect(ofs, s); - - if (hflip) - dst_rect.size.x = -dst_rect.size.x; - if (vflip) - dst_rect.size.y = -dst_rect.size.y; - - texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess)); - - } break; - } -} - -void AnimatedSprite::set_sprite_frames(const Ref &p_frames) { - - if (frames.is_valid()) - frames->disconnect("changed", callable_mp(this, &AnimatedSprite::_res_changed)); - frames = p_frames; - if (frames.is_valid()) - frames->connect("changed", callable_mp(this, &AnimatedSprite::_res_changed)); - - if (!frames.is_valid()) { - frame = 0; - } else { - set_frame(frame); - } - - _change_notify(); - _reset_timeout(); - update(); - update_configuration_warning(); -} - -Ref AnimatedSprite::get_sprite_frames() const { - - return frames; -} - -void AnimatedSprite::set_frame(int p_frame) { - - if (!frames.is_valid()) { - return; - } - - if (frames->has_animation(animation)) { - int limit = frames->get_frame_count(animation); - if (p_frame >= limit) - p_frame = limit - 1; - } - - if (p_frame < 0) - p_frame = 0; - - if (frame == p_frame) - return; - - frame = p_frame; - _reset_timeout(); - update(); - _change_notify("frame"); - emit_signal(SceneStringNames::get_singleton()->frame_changed); -} -int AnimatedSprite::get_frame() const { - - return frame; -} - -void AnimatedSprite::set_speed_scale(float p_speed_scale) { - - float elapsed = _get_frame_duration() - timeout; - - speed_scale = MAX(p_speed_scale, 0.0f); - - // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed - _reset_timeout(); - timeout -= elapsed; -} - -float AnimatedSprite::get_speed_scale() const { - - return speed_scale; -} - -void AnimatedSprite::set_centered(bool p_center) { - - centered = p_center; - update(); - item_rect_changed(); -} - -bool AnimatedSprite::is_centered() const { - - return centered; -} - -void AnimatedSprite::set_offset(const Point2 &p_offset) { - - offset = p_offset; - update(); - item_rect_changed(); - _change_notify("offset"); -} -Point2 AnimatedSprite::get_offset() const { - - return offset; -} - -void AnimatedSprite::set_flip_h(bool p_flip) { - - hflip = p_flip; - update(); -} -bool AnimatedSprite::is_flipped_h() const { - - return hflip; -} - -void AnimatedSprite::set_flip_v(bool p_flip) { - - vflip = p_flip; - update(); -} -bool AnimatedSprite::is_flipped_v() const { - - return vflip; -} - -void AnimatedSprite::_res_changed() { - - set_frame(frame); - _change_notify("frame"); - _change_notify("animation"); - update(); -} - -void AnimatedSprite::_set_playing(bool p_playing) { - - if (playing == p_playing) - return; - playing = p_playing; - _reset_timeout(); - set_process_internal(playing); -} - -bool AnimatedSprite::_is_playing() const { - - return playing; -} - -void AnimatedSprite::play(const StringName &p_animation, const bool p_backwards) { - - backwards = p_backwards; - - if (p_animation) { - set_animation(p_animation); - if (backwards && get_frame() == 0) - set_frame(frames->get_frame_count(p_animation) - 1); - } - - _set_playing(true); -} - -void AnimatedSprite::stop() { - - _set_playing(false); -} - -bool AnimatedSprite::is_playing() const { - - return playing; -} - -float AnimatedSprite::_get_frame_duration() { - if (frames.is_valid() && frames->has_animation(animation)) { - float speed = frames->get_animation_speed(animation) * speed_scale; - if (speed > 0) { - return 1.0 / speed; - } - } - return 0.0; -} - -void AnimatedSprite::_reset_timeout() { - - if (!playing) - return; - - timeout = _get_frame_duration(); - is_over = false; -} - -void AnimatedSprite::set_animation(const StringName &p_animation) { - - ERR_FAIL_COND_MSG(frames == NULL, vformat("There is no animation with name '%s'.", p_animation)); - ERR_FAIL_COND_MSG(frames->get_animation_names().find(p_animation) == -1, vformat("There is no animation with name '%s'.", p_animation)); - - if (animation == p_animation) - return; - - animation = p_animation; - _reset_timeout(); - set_frame(0); - _change_notify(); - update(); -} -StringName AnimatedSprite::get_animation() const { - - return animation; -} - -String AnimatedSprite::get_configuration_warning() const { - - if (frames.is_null()) { - return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."); - } - - return String(); -} - -void AnimatedSprite::set_specular_color(const Color &p_color) { - specular_color = p_color; - update(); -} - -Color AnimatedSprite::get_specular_color() const { - return specular_color; -} - -void AnimatedSprite::set_shininess(float p_shininess) { - shininess = CLAMP(p_shininess, 0.0, 1.0); - update(); -} - -float AnimatedSprite::get_shininess() const { - return shininess; -} - -void AnimatedSprite::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_sprite_frames", "sprite_frames"), &AnimatedSprite::set_sprite_frames); - ClassDB::bind_method(D_METHOD("get_sprite_frames"), &AnimatedSprite::get_sprite_frames); - - ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite::set_animation); - ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite::get_animation); - - ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite::_set_playing); - ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite::_is_playing); - - ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite::play, DEFVAL(StringName()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite::stop); - ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite::is_playing); - - ClassDB::bind_method(D_METHOD("set_centered", "centered"), &AnimatedSprite::set_centered); - ClassDB::bind_method(D_METHOD("is_centered"), &AnimatedSprite::is_centered); - - ClassDB::bind_method(D_METHOD("set_offset", "offset"), &AnimatedSprite::set_offset); - ClassDB::bind_method(D_METHOD("get_offset"), &AnimatedSprite::get_offset); - - ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &AnimatedSprite::set_flip_h); - ClassDB::bind_method(D_METHOD("is_flipped_h"), &AnimatedSprite::is_flipped_h); - - ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &AnimatedSprite::set_flip_v); - ClassDB::bind_method(D_METHOD("is_flipped_v"), &AnimatedSprite::is_flipped_v); - - ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite::set_frame); - ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite::get_frame); - - ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite::set_speed_scale); - ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite::get_speed_scale); - - ClassDB::bind_method(D_METHOD("set_specular_color", "color"), &AnimatedSprite::set_specular_color); - ClassDB::bind_method(D_METHOD("get_specular_color"), &AnimatedSprite::get_specular_color); - - ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &AnimatedSprite::set_shininess); - ClassDB::bind_method(D_METHOD("get_shininess"), &AnimatedSprite::get_shininess); - - ADD_SIGNAL(MethodInfo("frame_changed")); - ADD_SIGNAL(MethodInfo("animation_finished")); - - ADD_GROUP("Animation", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames"); - ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale"), "set_speed_scale", "get_speed_scale"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing"); - ADD_GROUP("Lighting", ""); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess"); - ADD_GROUP("Offset", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v"); -} - -AnimatedSprite::AnimatedSprite() { - - centered = true; - hflip = false; - vflip = false; - - frame = 0; - speed_scale = 1.0f; - playing = false; - backwards = false; - animation = "default"; - timeout = 0; - is_over = false; - specular_color = Color(1, 1, 1, 1); - shininess = 1.0; -} diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h deleted file mode 100644 index e5d015b07c..0000000000 --- a/scene/2d/animated_sprite.h +++ /dev/null @@ -1,231 +0,0 @@ -/*************************************************************************/ -/* animated_sprite.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 ANIMATED_SPRITE_H -#define ANIMATED_SPRITE_H - -#include "scene/2d/node_2d.h" -#include "scene/resources/texture.h" - -class SpriteFrames : public Resource { - - GDCLASS(SpriteFrames, Resource); - - struct Anim { - - float speed; - bool loop; - Vector> frames; - - Anim() { - loop = true; - speed = 5; - } - - StringName normal_name; - StringName specular_name; - }; - - Color specular_color; - float shininess; - - Map animations; - - Array _get_frames() const; - void _set_frames(const Array &p_frames); - - Array _get_animations() const; - void _set_animations(const Array &p_animations); - - Vector _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 *r_animations) const; - Vector 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 &p_frame, int p_at_pos = -1); - int get_frame_count(const StringName &p_anim) const; - _FORCE_INLINE_ Ref get_frame(const StringName &p_anim, int p_idx) const { - - const Map::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, Ref(), "Animation '" + String(p_anim) + "' doesn't exist."); - ERR_FAIL_COND_V(p_idx < 0, Ref()); - if (p_idx >= E->get().frames.size()) - return Ref(); - - return E->get().frames[p_idx]; - } - - _FORCE_INLINE_ Ref get_normal_frame(const StringName &p_anim, int p_idx) const { - - const Map::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, Ref(), "Animation '" + String(p_anim) + "' doesn't exist."); - ERR_FAIL_COND_V(p_idx < 0, Ref()); - - const Map::Element *EN = animations.find(E->get().normal_name); - - if (!EN || p_idx >= EN->get().frames.size()) - return Ref(); - - return EN->get().frames[p_idx]; - } - - _FORCE_INLINE_ Ref get_specular_frame(const StringName &p_anim, int p_idx) const { - - const Map::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V(!E, Ref()); - ERR_FAIL_COND_V(p_idx < 0, Ref()); - - const Map::Element *EN = animations.find(E->get().specular_name); - - if (!EN || p_idx >= EN->get().frames.size()) - return Ref(); - - return EN->get().frames[p_idx]; - } - - void set_frame(const StringName &p_anim, int p_idx, const Ref &p_frame) { - Map::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 AnimatedSprite : public Node2D { - - GDCLASS(AnimatedSprite, Node2D); - - Ref frames; - bool playing; - bool backwards; - StringName animation; - int frame; - float speed_scale; - - bool centered; - Point2 offset; - - bool is_over; - float timeout; - - bool hflip; - bool vflip; - - void _res_changed(); - - float _get_frame_duration(); - void _reset_timeout(); - void _set_playing(bool p_playing); - bool _is_playing() const; - Rect2 _get_rect() const; - - Color specular_color; - float shininess; - -protected: - static void _bind_methods(); - void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const; - -public: -#ifdef TOOLS_ENABLED - virtual Dictionary _edit_get_state() const; - virtual void _edit_set_state(const Dictionary &p_state); - - virtual void _edit_set_pivot(const Point2 &p_pivot); - virtual Point2 _edit_get_pivot() const; - virtual bool _edit_use_pivot() const; - virtual Rect2 _edit_get_rect() const; - virtual bool _edit_use_rect() const; -#endif - - virtual Rect2 get_anchorable_rect() const; - - void set_sprite_frames(const Ref &p_frames); - Ref get_sprite_frames() const; - - void play(const StringName &p_animation = StringName(), const bool p_backwards = false); - void stop(); - bool is_playing() const; - - void set_animation(const StringName &p_animation); - StringName get_animation() const; - - void set_frame(int p_frame); - int get_frame() const; - - void set_speed_scale(float p_speed_scale); - float get_speed_scale() const; - - void set_centered(bool p_center); - bool is_centered() const; - - void set_offset(const Point2 &p_offset); - Point2 get_offset() const; - - void set_flip_h(bool p_flip); - bool is_flipped_h() const; - - void set_flip_v(bool p_flip); - bool is_flipped_v() const; - - void set_specular_color(const Color &p_color); - Color get_specular_color() const; - - void set_shininess(float p_shininess); - float get_shininess() const; - - virtual String get_configuration_warning() const; - AnimatedSprite(); -}; - -#endif // ANIMATED_SPRITE_H diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp new file mode 100644 index 0000000000..4cedfc0c20 --- /dev/null +++ b/scene/2d/animated_sprite_2d.cpp @@ -0,0 +1,772 @@ +/*************************************************************************/ +/* animated_sprite_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "animated_sprite_2d.h" + +#include "core/os/os.h" +#include "scene/scene_string_names.h" + +#define NORMAL_SUFFIX "_normal" +#define SPECULAR_SUFFIX "_specular" + +#ifdef TOOLS_ENABLED +Dictionary AnimatedSprite2D::_edit_get_state() const { + Dictionary state = Node2D::_edit_get_state(); + state["offset"] = offset; + return state; +} + +void AnimatedSprite2D::_edit_set_state(const Dictionary &p_state) { + Node2D::_edit_set_state(p_state); + set_offset(p_state["offset"]); +} + +void AnimatedSprite2D::_edit_set_pivot(const Point2 &p_pivot) { + set_offset(get_offset() - p_pivot); + set_position(get_transform().xform(p_pivot)); +} + +Point2 AnimatedSprite2D::_edit_get_pivot() const { + return Vector2(); +} + +bool AnimatedSprite2D::_edit_use_pivot() const { + return true; +} + +Rect2 AnimatedSprite2D::_edit_get_rect() const { + return _get_rect(); +} + +bool AnimatedSprite2D::_edit_use_rect() const { + if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) { + return false; + } + Ref t; + if (animation) + t = frames->get_frame(animation, frame); + return t.is_valid(); +} +#endif + +Rect2 AnimatedSprite2D::get_anchorable_rect() const { + return _get_rect(); +} + +Rect2 AnimatedSprite2D::_get_rect() const { + if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) { + return Rect2(); + } + + Ref t; + if (animation) + t = frames->get_frame(animation, frame); + if (t.is_null()) + return Rect2(); + Size2 s = t->get_size(); + + Point2 ofs = offset; + if (centered) + ofs -= Size2(s) / 2; + + if (s == Size2(0, 0)) + s = Size2(1, 1); + + return Rect2(ofs, s); +} + +void SpriteFrames::add_frame(const StringName &p_anim, const Ref &p_frame, int p_at_pos) { + + Map::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::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::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::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(); + animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX; + animations[p_anim].specular_name = String(p_anim) + SPECULAR_SUFFIX; +} + +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; + animations[p_next].normal_name = String(p_next) + NORMAL_SUFFIX; + animations[p_next].specular_name = String(p_next) + SPECULAR_SUFFIX; +} + +Vector SpriteFrames::_get_animation_list() const { + + Vector ret; + List al; + get_animation_list(&al); + for (List::Element *E = al.front(); E; E = E->next()) { + + ret.push_back(E->get()); + } + + return ret; +} + +void SpriteFrames::get_animation_list(List *r_animations) const { + + for (const Map::Element *E = animations.front(); E; E = E->next()) { + r_animations->push_back(E->key()); + } +} + +Vector SpriteFrames::get_animation_names() const { + + Vector names; + for (const Map::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::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::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::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::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::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::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; + if (property.name == "animation") { + + property.hint = PROPERTY_HINT_ENUM; + List names; + frames->get_animation_list(&names); + names.sort_custom(); + + bool current_found = false; + + for (List::Element *E = names.front(); E; E = E->next()) { + if (E->prev()) { + property.hint_string += ","; + } + + property.hint_string += String(E->get()); + if (animation == E->get()) { + current_found = true; + } + } + + if (!current_found) { + if (property.hint_string == String()) { + property.hint_string = String(animation); + } else { + property.hint_string = String(animation) + "," + property.hint_string; + } + } + } + + if (property.name == "frame") { + property.hint = PROPERTY_HINT_RANGE; + if (frames->has_animation(animation) && frames->get_frame_count(animation) > 1) { + property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; + } + property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; + } +} + +void AnimatedSprite2D::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_INTERNAL_PROCESS: { + + if (frames.is_null()) + return; + if (!frames->has_animation(animation)) + return; + if (frame < 0) + return; + + float speed = frames->get_animation_speed(animation) * speed_scale; + if (speed == 0) + return; //do nothing + + float remaining = get_process_delta_time(); + + while (remaining) { + + if (timeout <= 0) { + + timeout = _get_frame_duration(); + + int fc = frames->get_frame_count(animation); + if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) { + if (frames->get_animation_loop(animation)) { + if (backwards) + frame = fc - 1; + else + frame = 0; + + emit_signal(SceneStringNames::get_singleton()->animation_finished); + } else { + if (backwards) + frame = 0; + else + frame = fc - 1; + + if (!is_over) { + is_over = true; + emit_signal(SceneStringNames::get_singleton()->animation_finished); + } + } + } else { + if (backwards) + frame--; + else + frame++; + } + + update(); + _change_notify("frame"); + emit_signal(SceneStringNames::get_singleton()->frame_changed); + } + + float to_process = MIN(timeout, remaining); + remaining -= to_process; + timeout -= to_process; + } + } break; + + case NOTIFICATION_DRAW: { + + if (frames.is_null()) + return; + if (frame < 0) + return; + if (!frames->has_animation(animation)) + return; + + Ref texture = frames->get_frame(animation, frame); + if (texture.is_null()) + return; + + Ref normal = frames->get_normal_frame(animation, frame); + Ref specular = frames->get_specular_frame(animation, frame); + + RID ci = get_canvas_item(); + + Size2i s; + s = texture->get_size(); + Point2 ofs = offset; + if (centered) + ofs -= s / 2; + + if (Engine::get_singleton()->get_use_pixel_snap()) { + ofs = ofs.floor(); + } + Rect2 dst_rect(ofs, s); + + if (hflip) + dst_rect.size.x = -dst_rect.size.x; + if (vflip) + dst_rect.size.y = -dst_rect.size.y; + + texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess)); + + } break; + } +} + +void AnimatedSprite2D::set_sprite_frames(const Ref &p_frames) { + + if (frames.is_valid()) + frames->disconnect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed)); + frames = p_frames; + if (frames.is_valid()) + frames->connect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed)); + + if (!frames.is_valid()) { + frame = 0; + } else { + set_frame(frame); + } + + _change_notify(); + _reset_timeout(); + update(); + update_configuration_warning(); +} + +Ref AnimatedSprite2D::get_sprite_frames() const { + + return frames; +} + +void AnimatedSprite2D::set_frame(int p_frame) { + + if (!frames.is_valid()) { + return; + } + + if (frames->has_animation(animation)) { + int limit = frames->get_frame_count(animation); + if (p_frame >= limit) + p_frame = limit - 1; + } + + if (p_frame < 0) + p_frame = 0; + + if (frame == p_frame) + return; + + frame = p_frame; + _reset_timeout(); + update(); + _change_notify("frame"); + emit_signal(SceneStringNames::get_singleton()->frame_changed); +} +int AnimatedSprite2D::get_frame() const { + + return frame; +} + +void AnimatedSprite2D::set_speed_scale(float p_speed_scale) { + + float elapsed = _get_frame_duration() - timeout; + + speed_scale = MAX(p_speed_scale, 0.0f); + + // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed + _reset_timeout(); + timeout -= elapsed; +} + +float AnimatedSprite2D::get_speed_scale() const { + + return speed_scale; +} + +void AnimatedSprite2D::set_centered(bool p_center) { + + centered = p_center; + update(); + item_rect_changed(); +} + +bool AnimatedSprite2D::is_centered() const { + + return centered; +} + +void AnimatedSprite2D::set_offset(const Point2 &p_offset) { + + offset = p_offset; + update(); + item_rect_changed(); + _change_notify("offset"); +} +Point2 AnimatedSprite2D::get_offset() const { + + return offset; +} + +void AnimatedSprite2D::set_flip_h(bool p_flip) { + + hflip = p_flip; + update(); +} +bool AnimatedSprite2D::is_flipped_h() const { + + return hflip; +} + +void AnimatedSprite2D::set_flip_v(bool p_flip) { + + vflip = p_flip; + update(); +} +bool AnimatedSprite2D::is_flipped_v() const { + + return vflip; +} + +void AnimatedSprite2D::_res_changed() { + + set_frame(frame); + _change_notify("frame"); + _change_notify("animation"); + update(); +} + +void AnimatedSprite2D::_set_playing(bool p_playing) { + + if (playing == p_playing) + return; + playing = p_playing; + _reset_timeout(); + set_process_internal(playing); +} + +bool AnimatedSprite2D::_is_playing() const { + + return playing; +} + +void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backwards) { + + backwards = p_backwards; + + if (p_animation) { + set_animation(p_animation); + if (backwards && get_frame() == 0) + set_frame(frames->get_frame_count(p_animation) - 1); + } + + _set_playing(true); +} + +void AnimatedSprite2D::stop() { + + _set_playing(false); +} + +bool AnimatedSprite2D::is_playing() const { + + return playing; +} + +float AnimatedSprite2D::_get_frame_duration() { + if (frames.is_valid() && frames->has_animation(animation)) { + float speed = frames->get_animation_speed(animation) * speed_scale; + if (speed > 0) { + return 1.0 / speed; + } + } + return 0.0; +} + +void AnimatedSprite2D::_reset_timeout() { + + if (!playing) + return; + + timeout = _get_frame_duration(); + is_over = false; +} + +void AnimatedSprite2D::set_animation(const StringName &p_animation) { + + ERR_FAIL_COND_MSG(frames == NULL, vformat("There is no animation with name '%s'.", p_animation)); + ERR_FAIL_COND_MSG(frames->get_animation_names().find(p_animation) == -1, vformat("There is no animation with name '%s'.", p_animation)); + + if (animation == p_animation) + return; + + animation = p_animation; + _reset_timeout(); + set_frame(0); + _change_notify(); + update(); +} +StringName AnimatedSprite2D::get_animation() const { + + return animation; +} + +String AnimatedSprite2D::get_configuration_warning() const { + + if (frames.is_null()) { + return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."); + } + + return String(); +} + +void AnimatedSprite2D::set_specular_color(const Color &p_color) { + specular_color = p_color; + update(); +} + +Color AnimatedSprite2D::get_specular_color() const { + return specular_color; +} + +void AnimatedSprite2D::set_shininess(float p_shininess) { + shininess = CLAMP(p_shininess, 0.0, 1.0); + update(); +} + +float AnimatedSprite2D::get_shininess() const { + return shininess; +} + +void AnimatedSprite2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_sprite_frames", "sprite_frames"), &AnimatedSprite2D::set_sprite_frames); + ClassDB::bind_method(D_METHOD("get_sprite_frames"), &AnimatedSprite2D::get_sprite_frames); + + ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite2D::set_animation); + ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite2D::get_animation); + + ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite2D::_set_playing); + ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite2D::_is_playing); + + ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite2D::play, DEFVAL(StringName()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite2D::stop); + ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite2D::is_playing); + + ClassDB::bind_method(D_METHOD("set_centered", "centered"), &AnimatedSprite2D::set_centered); + ClassDB::bind_method(D_METHOD("is_centered"), &AnimatedSprite2D::is_centered); + + ClassDB::bind_method(D_METHOD("set_offset", "offset"), &AnimatedSprite2D::set_offset); + ClassDB::bind_method(D_METHOD("get_offset"), &AnimatedSprite2D::get_offset); + + ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &AnimatedSprite2D::set_flip_h); + ClassDB::bind_method(D_METHOD("is_flipped_h"), &AnimatedSprite2D::is_flipped_h); + + ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &AnimatedSprite2D::set_flip_v); + ClassDB::bind_method(D_METHOD("is_flipped_v"), &AnimatedSprite2D::is_flipped_v); + + ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite2D::set_frame); + ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite2D::get_frame); + + ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite2D::set_speed_scale); + ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite2D::get_speed_scale); + + ClassDB::bind_method(D_METHOD("set_specular_color", "color"), &AnimatedSprite2D::set_specular_color); + ClassDB::bind_method(D_METHOD("get_specular_color"), &AnimatedSprite2D::get_specular_color); + + ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &AnimatedSprite2D::set_shininess); + ClassDB::bind_method(D_METHOD("get_shininess"), &AnimatedSprite2D::get_shininess); + + ADD_SIGNAL(MethodInfo("frame_changed")); + ADD_SIGNAL(MethodInfo("animation_finished")); + + ADD_GROUP("Animation", ""); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing"); + ADD_GROUP("Lighting", ""); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess"); + ADD_GROUP("Offset", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v"); +} + +AnimatedSprite2D::AnimatedSprite2D() { + + centered = true; + hflip = false; + vflip = false; + + frame = 0; + speed_scale = 1.0f; + playing = false; + backwards = false; + animation = "default"; + timeout = 0; + is_over = false; + specular_color = Color(1, 1, 1, 1); + shininess = 1.0; +} diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h new file mode 100644 index 0000000000..726ecefd32 --- /dev/null +++ b/scene/2d/animated_sprite_2d.h @@ -0,0 +1,231 @@ +/*************************************************************************/ +/* animated_sprite_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 ANIMATED_SPRITE_2D_H +#define ANIMATED_SPRITE_2D_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/texture.h" + +class SpriteFrames : public Resource { + + GDCLASS(SpriteFrames, Resource); + + struct Anim { + + float speed; + bool loop; + Vector> frames; + + Anim() { + loop = true; + speed = 5; + } + + StringName normal_name; + StringName specular_name; + }; + + Color specular_color; + float shininess; + + Map animations; + + Array _get_frames() const; + void _set_frames(const Array &p_frames); + + Array _get_animations() const; + void _set_animations(const Array &p_animations); + + Vector _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 *r_animations) const; + Vector 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 &p_frame, int p_at_pos = -1); + int get_frame_count(const StringName &p_anim) const; + _FORCE_INLINE_ Ref get_frame(const StringName &p_anim, int p_idx) const { + + const Map::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, Ref(), "Animation '" + String(p_anim) + "' doesn't exist."); + ERR_FAIL_COND_V(p_idx < 0, Ref()); + if (p_idx >= E->get().frames.size()) + return Ref(); + + return E->get().frames[p_idx]; + } + + _FORCE_INLINE_ Ref get_normal_frame(const StringName &p_anim, int p_idx) const { + + const Map::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, Ref(), "Animation '" + String(p_anim) + "' doesn't exist."); + ERR_FAIL_COND_V(p_idx < 0, Ref()); + + const Map::Element *EN = animations.find(E->get().normal_name); + + if (!EN || p_idx >= EN->get().frames.size()) + return Ref(); + + return EN->get().frames[p_idx]; + } + + _FORCE_INLINE_ Ref get_specular_frame(const StringName &p_anim, int p_idx) const { + + const Map::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V(!E, Ref()); + ERR_FAIL_COND_V(p_idx < 0, Ref()); + + const Map::Element *EN = animations.find(E->get().specular_name); + + if (!EN || p_idx >= EN->get().frames.size()) + return Ref(); + + return EN->get().frames[p_idx]; + } + + void set_frame(const StringName &p_anim, int p_idx, const Ref &p_frame) { + Map::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); + + Ref frames; + bool playing; + bool backwards; + StringName animation; + int frame; + float speed_scale; + + bool centered; + Point2 offset; + + bool is_over; + float timeout; + + bool hflip; + bool vflip; + + void _res_changed(); + + float _get_frame_duration(); + void _reset_timeout(); + void _set_playing(bool p_playing); + bool _is_playing() const; + Rect2 _get_rect() const; + + Color specular_color; + float shininess; + +protected: + static void _bind_methods(); + void _notification(int p_what); + virtual void _validate_property(PropertyInfo &property) const; + +public: +#ifdef TOOLS_ENABLED + virtual Dictionary _edit_get_state() const; + virtual void _edit_set_state(const Dictionary &p_state); + + virtual void _edit_set_pivot(const Point2 &p_pivot); + virtual Point2 _edit_get_pivot() const; + virtual bool _edit_use_pivot() const; + virtual Rect2 _edit_get_rect() const; + virtual bool _edit_use_rect() const; +#endif + + virtual Rect2 get_anchorable_rect() const; + + void set_sprite_frames(const Ref &p_frames); + Ref get_sprite_frames() const; + + void play(const StringName &p_animation = StringName(), const bool p_backwards = false); + void stop(); + bool is_playing() const; + + void set_animation(const StringName &p_animation); + StringName get_animation() const; + + void set_frame(int p_frame); + int get_frame() const; + + void set_speed_scale(float p_speed_scale); + float get_speed_scale() const; + + void set_centered(bool p_center); + bool is_centered() const; + + void set_offset(const Point2 &p_offset); + Point2 get_offset() const; + + void set_flip_h(bool p_flip); + bool is_flipped_h() const; + + void set_flip_v(bool p_flip); + bool is_flipped_v() const; + + void set_specular_color(const Color &p_color); + Color get_specular_color() const; + + void set_shininess(float p_shininess); + float get_shininess() const; + + virtual String get_configuration_warning() const; + AnimatedSprite2D(); +}; + +#endif // ANIMATED_SPRITE_H diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp deleted file mode 100644 index a6fb6f7435..0000000000 --- a/scene/2d/sprite.cpp +++ /dev/null @@ -1,539 +0,0 @@ -/*************************************************************************/ -/* sprite.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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.h" - -#include "core/core_string_names.h" -#include "core/os/os.h" -#include "scene/main/window.h" -#include "scene/scene_string_names.h" - -#ifdef TOOLS_ENABLED -Dictionary Sprite::_edit_get_state() const { - Dictionary state = Node2D::_edit_get_state(); - state["offset"] = offset; - return state; -} - -void Sprite::_edit_set_state(const Dictionary &p_state) { - Node2D::_edit_set_state(p_state); - set_offset(p_state["offset"]); -} - -void Sprite::_edit_set_pivot(const Point2 &p_pivot) { - set_offset(get_offset() - p_pivot); - set_position(get_transform().xform(p_pivot)); -} - -Point2 Sprite::_edit_get_pivot() const { - return Vector2(); -} - -bool Sprite::_edit_use_pivot() const { - return true; -} - -bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - - return is_pixel_opaque(p_point); -} - -Rect2 Sprite::_edit_get_rect() const { - return get_rect(); -} - -bool Sprite::_edit_use_rect() const { - return texture.is_valid(); -} -#endif - -Rect2 Sprite::get_anchorable_rect() const { - return get_rect(); -} - -void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const { - - Rect2 base_rect; - - if (region) { - r_filter_clip = region_filter_clip; - base_rect = region_rect; - } else { - r_filter_clip = false; - base_rect = Rect2(0, 0, texture->get_width(), texture->get_height()); - } - - Size2 frame_size = base_rect.size / Size2(hframes, vframes); - Point2 frame_offset = Point2(frame % hframes, frame / hframes); - frame_offset *= frame_size; - - r_src_rect.size = frame_size; - r_src_rect.position = base_rect.position + frame_offset; - - Point2 dest_offset = offset; - if (centered) - dest_offset -= frame_size / 2; - if (Engine::get_singleton()->get_use_pixel_snap()) { - dest_offset = dest_offset.floor(); - } - - r_dst_rect = Rect2(dest_offset, frame_size); - - if (hflip) - r_dst_rect.size.x = -r_dst_rect.size.x; - if (vflip) - r_dst_rect.size.y = -r_dst_rect.size.y; -} - -void Sprite::_notification(int p_what) { - - switch (p_what) { - - case NOTIFICATION_DRAW: { - - if (texture.is_null()) - return; - - RID ci = get_canvas_item(); - - /* - texture->draw(ci,Point2()); - break; - */ - - Rect2 src_rect, dst_rect; - bool filter_clip; - _get_rects(src_rect, dst_rect, filter_clip); - texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess), VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, filter_clip); - - } break; - } -} - -void Sprite::set_texture(const Ref &p_texture) { - - if (p_texture == texture) - return; - - if (texture.is_valid()) - texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite::_texture_changed)); - - texture = p_texture; - - if (texture.is_valid()) - texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite::_texture_changed)); - - update(); - emit_signal("texture_changed"); - item_rect_changed(); - _change_notify("texture"); -} - -void Sprite::set_normal_map(const Ref &p_texture) { - - normal_map = p_texture; - update(); -} - -Ref Sprite::get_normal_map() const { - - return normal_map; -} - -void Sprite::set_specular_map(const Ref &p_texture) { - - specular = p_texture; - update(); -} - -Ref Sprite::get_specular_map() const { - - return specular; -} - -void Sprite::set_specular_color(const Color &p_color) { - specular_color = p_color; - update(); -} - -Color Sprite::get_specular_color() const { - return specular_color; -} - -void Sprite::set_shininess(float p_shininess) { - shininess = CLAMP(p_shininess, 0.0, 1.0); - update(); -} - -float Sprite::get_shininess() const { - return shininess; -} - -Ref Sprite::get_texture() const { - - return texture; -} - -void Sprite::set_centered(bool p_center) { - - centered = p_center; - update(); - item_rect_changed(); -} - -bool Sprite::is_centered() const { - - return centered; -} - -void Sprite::set_offset(const Point2 &p_offset) { - - offset = p_offset; - update(); - item_rect_changed(); - _change_notify("offset"); -} -Point2 Sprite::get_offset() const { - - return offset; -} - -void Sprite::set_flip_h(bool p_flip) { - - hflip = p_flip; - update(); -} -bool Sprite::is_flipped_h() const { - - return hflip; -} - -void Sprite::set_flip_v(bool p_flip) { - - vflip = p_flip; - update(); -} -bool Sprite::is_flipped_v() const { - - return vflip; -} - -void Sprite::set_region(bool p_region) { - - if (p_region == region) - return; - - region = p_region; - update(); -} - -bool Sprite::is_region() const { - - return region; -} - -void Sprite::set_region_rect(const Rect2 &p_region_rect) { - - if (region_rect == p_region_rect) - return; - - region_rect = p_region_rect; - - if (region) - item_rect_changed(); - - _change_notify("region_rect"); -} - -Rect2 Sprite::get_region_rect() const { - - return region_rect; -} - -void Sprite::set_region_filter_clip(bool p_enable) { - region_filter_clip = p_enable; - update(); -} - -bool Sprite::is_region_filter_clip_enabled() const { - return region_filter_clip; -} - -void Sprite::set_frame(int p_frame) { - - ERR_FAIL_INDEX(p_frame, vframes * hframes); - - if (frame != p_frame) - item_rect_changed(); - - frame = p_frame; - - _change_notify("frame"); - _change_notify("frame_coords"); - emit_signal(SceneStringNames::get_singleton()->frame_changed); -} - -int Sprite::get_frame() const { - - return frame; -} - -void Sprite::set_frame_coords(const Vector2 &p_coord) { - ERR_FAIL_INDEX(int(p_coord.x), hframes); - ERR_FAIL_INDEX(int(p_coord.y), vframes); - - set_frame(int(p_coord.y) * hframes + int(p_coord.x)); -} - -Vector2 Sprite::get_frame_coords() const { - return Vector2(frame % hframes, frame / hframes); -} - -void Sprite::set_vframes(int p_amount) { - - ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1."); - vframes = p_amount; - update(); - item_rect_changed(); - _change_notify(); -} -int Sprite::get_vframes() const { - - return vframes; -} - -void Sprite::set_hframes(int p_amount) { - - ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1."); - hframes = p_amount; - update(); - item_rect_changed(); - _change_notify(); -} -int Sprite::get_hframes() const { - - return hframes; -} - -bool Sprite::is_pixel_opaque(const Point2 &p_point) const { - - if (texture.is_null()) - return false; - - if (texture->get_size().width == 0 || texture->get_size().height == 0) - return false; - - Rect2 src_rect, dst_rect; - bool filter_clip; - _get_rects(src_rect, dst_rect, filter_clip); - dst_rect.size = dst_rect.size.abs(); - - if (!dst_rect.has_point(p_point)) - return false; - - Vector2 q = (p_point - dst_rect.position) / dst_rect.size; - if (hflip) - q.x = 1.0f - q.x; - if (vflip) - q.y = 1.0f - q.y; - q = q * src_rect.size + src_rect.position; -#ifndef _MSC_VER -#warning this need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that) -#endif - bool is_repeat = false; - bool is_mirrored_repeat = false; - if (is_repeat) { - int mirror_x = 0; - int mirror_y = 0; - if (is_mirrored_repeat) { - mirror_x = (int)(q.x / texture->get_size().width); - mirror_y = (int)(q.y / texture->get_size().height); - } - q.x = Math::fmod(q.x, texture->get_size().width); - q.y = Math::fmod(q.y, texture->get_size().height); - if (mirror_x % 2 == 1) { - q.x = texture->get_size().width - q.x - 1; - } - if (mirror_y % 2 == 1) { - q.y = texture->get_size().height - q.y - 1; - } - } else { - q.x = MIN(q.x, texture->get_size().width - 1); - q.y = MIN(q.y, texture->get_size().height - 1); - } - - return texture->is_pixel_opaque((int)q.x, (int)q.y); -} - -Rect2 Sprite::get_rect() const { - - if (texture.is_null()) - return Rect2(0, 0, 1, 1); - - Size2i s; - - if (region) { - s = region_rect.size; - } else { - s = texture->get_size(); - } - - s = s / Point2(hframes, vframes); - - Point2 ofs = offset; - if (centered) - ofs -= Size2(s) / 2; - - if (s == Size2(0, 0)) - s = Size2(1, 1); - - return Rect2(ofs, s); -} - -void Sprite::_validate_property(PropertyInfo &property) const { - - if (property.name == "frame") { - property.hint = PROPERTY_HINT_RANGE; - property.hint_string = "0," + itos(vframes * hframes - 1) + ",1"; - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; - } - - if (property.name == "frame_coords") { - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; - } -} - -void Sprite::_texture_changed() { - - // Changes to the texture need to trigger an update to make - // the editor redraw the sprite with the updated texture. - if (texture.is_valid()) { - update(); - } -} - -void Sprite::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &Sprite::get_texture); - - ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &Sprite::set_normal_map); - ClassDB::bind_method(D_METHOD("get_normal_map"), &Sprite::get_normal_map); - - ClassDB::bind_method(D_METHOD("set_specular_map", "specular_map"), &Sprite::set_specular_map); - ClassDB::bind_method(D_METHOD("get_specular_map"), &Sprite::get_specular_map); - - ClassDB::bind_method(D_METHOD("set_specular_color", "specular_color"), &Sprite::set_specular_color); - ClassDB::bind_method(D_METHOD("get_specular_color"), &Sprite::get_specular_color); - - ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &Sprite::set_shininess); - ClassDB::bind_method(D_METHOD("get_shininess"), &Sprite::get_shininess); - - ClassDB::bind_method(D_METHOD("set_centered", "centered"), &Sprite::set_centered); - ClassDB::bind_method(D_METHOD("is_centered"), &Sprite::is_centered); - - ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Sprite::set_offset); - ClassDB::bind_method(D_METHOD("get_offset"), &Sprite::get_offset); - - ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &Sprite::set_flip_h); - ClassDB::bind_method(D_METHOD("is_flipped_h"), &Sprite::is_flipped_h); - - ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &Sprite::set_flip_v); - ClassDB::bind_method(D_METHOD("is_flipped_v"), &Sprite::is_flipped_v); - - ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite::set_region); - ClassDB::bind_method(D_METHOD("is_region"), &Sprite::is_region); - - ClassDB::bind_method(D_METHOD("is_pixel_opaque", "pos"), &Sprite::is_pixel_opaque); - - ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite::set_region_rect); - ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite::get_region_rect); - - ClassDB::bind_method(D_METHOD("set_region_filter_clip", "enabled"), &Sprite::set_region_filter_clip); - ClassDB::bind_method(D_METHOD("is_region_filter_clip_enabled"), &Sprite::is_region_filter_clip_enabled); - - ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite::set_frame); - ClassDB::bind_method(D_METHOD("get_frame"), &Sprite::get_frame); - - ClassDB::bind_method(D_METHOD("set_frame_coords", "coords"), &Sprite::set_frame_coords); - ClassDB::bind_method(D_METHOD("get_frame_coords"), &Sprite::get_frame_coords); - - ClassDB::bind_method(D_METHOD("set_vframes", "vframes"), &Sprite::set_vframes); - ClassDB::bind_method(D_METHOD("get_vframes"), &Sprite::get_vframes); - - ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite::set_hframes); - ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite::get_hframes); - - ClassDB::bind_method(D_METHOD("get_rect"), &Sprite::get_rect); - - ADD_SIGNAL(MethodInfo("frame_changed")); - ADD_SIGNAL(MethodInfo("texture_changed")); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_GROUP("Lighting", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_map", "get_specular_map"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess"); - ADD_GROUP("Offset", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v"); - ADD_GROUP("Animation", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); - - ADD_GROUP("Region", "region_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region"); - ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_filter_clip"), "set_region_filter_clip", "is_region_filter_clip_enabled"); -} - -Sprite::Sprite() { - - centered = true; - hflip = false; - vflip = false; - region = false; - region_filter_clip = false; - shininess = 1.0; - specular_color = Color(1, 1, 1, 1); - - frame = 0; - - vframes = 1; - hframes = 1; -} - -Sprite::~Sprite() { -} diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h deleted file mode 100644 index a96f023231..0000000000 --- a/scene/2d/sprite.h +++ /dev/null @@ -1,143 +0,0 @@ -/*************************************************************************/ -/* sprite.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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_H -#define SPRITE_H - -#include "scene/2d/node_2d.h" -#include "scene/resources/texture.h" - -class Sprite : public Node2D { - - GDCLASS(Sprite, Node2D); - - Ref texture; - Ref normal_map; - Ref specular; - Color specular_color; - float shininess; - - bool centered; - Point2 offset; - - bool hflip; - bool vflip; - bool region; - Rect2 region_rect; - bool region_filter_clip; - - int frame; - - int vframes; - int hframes; - - void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const; - - void _texture_changed(); - -protected: - void _notification(int p_what); - - static void _bind_methods(); - - virtual void _validate_property(PropertyInfo &property) const; - -public: -#ifdef TOOLS_ENABLED - virtual Dictionary _edit_get_state() const; - virtual void _edit_set_state(const Dictionary &p_state); - - virtual void _edit_set_pivot(const Point2 &p_pivot); - virtual Point2 _edit_get_pivot() const; - virtual bool _edit_use_pivot() const; - virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; - - virtual Rect2 _edit_get_rect() const; - virtual bool _edit_use_rect() const; -#endif - - bool is_pixel_opaque(const Point2 &p_point) const; - - void set_texture(const Ref &p_texture); - Ref get_texture() const; - - void set_normal_map(const Ref &p_texture); - Ref get_normal_map() const; - - void set_specular_map(const Ref &p_texture); - Ref get_specular_map() const; - - void set_specular_color(const Color &p_color); - Color get_specular_color() const; - - void set_shininess(float p_shininess); - float get_shininess() const; - - void set_centered(bool p_center); - bool is_centered() const; - - void set_offset(const Point2 &p_offset); - Point2 get_offset() const; - - void set_flip_h(bool p_flip); - bool is_flipped_h() const; - - void set_flip_v(bool p_flip); - bool is_flipped_v() const; - - void set_region(bool p_region); - bool is_region() const; - - void set_region_filter_clip(bool p_enable); - bool is_region_filter_clip_enabled() const; - - void set_region_rect(const Rect2 &p_region_rect); - Rect2 get_region_rect() const; - - void set_frame(int p_frame); - int get_frame() const; - - void set_frame_coords(const Vector2 &p_coord); - Vector2 get_frame_coords() const; - - void set_vframes(int p_amount); - int get_vframes() const; - - void set_hframes(int p_amount); - int get_hframes() const; - - Rect2 get_rect() const; - virtual Rect2 get_anchorable_rect() const; - - Sprite(); - ~Sprite(); -}; - -#endif // SPRITE_H diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp new file mode 100644 index 0000000000..d45fe9a2a5 --- /dev/null +++ b/scene/2d/sprite_2d.cpp @@ -0,0 +1,539 @@ +/*************************************************************************/ +/* sprite_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_2d.h" + +#include "core/core_string_names.h" +#include "core/os/os.h" +#include "scene/main/window.h" +#include "scene/scene_string_names.h" + +#ifdef TOOLS_ENABLED +Dictionary Sprite2D::_edit_get_state() const { + Dictionary state = Node2D::_edit_get_state(); + state["offset"] = offset; + return state; +} + +void Sprite2D::_edit_set_state(const Dictionary &p_state) { + Node2D::_edit_set_state(p_state); + set_offset(p_state["offset"]); +} + +void Sprite2D::_edit_set_pivot(const Point2 &p_pivot) { + set_offset(get_offset() - p_pivot); + set_position(get_transform().xform(p_pivot)); +} + +Point2 Sprite2D::_edit_get_pivot() const { + return Vector2(); +} + +bool Sprite2D::_edit_use_pivot() const { + return true; +} + +bool Sprite2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + + return is_pixel_opaque(p_point); +} + +Rect2 Sprite2D::_edit_get_rect() const { + return get_rect(); +} + +bool Sprite2D::_edit_use_rect() const { + return texture.is_valid(); +} +#endif + +Rect2 Sprite2D::get_anchorable_rect() const { + return get_rect(); +} + +void Sprite2D::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const { + + Rect2 base_rect; + + if (region) { + r_filter_clip = region_filter_clip; + base_rect = region_rect; + } else { + r_filter_clip = false; + base_rect = Rect2(0, 0, texture->get_width(), texture->get_height()); + } + + Size2 frame_size = base_rect.size / Size2(hframes, vframes); + Point2 frame_offset = Point2(frame % hframes, frame / hframes); + frame_offset *= frame_size; + + r_src_rect.size = frame_size; + r_src_rect.position = base_rect.position + frame_offset; + + Point2 dest_offset = offset; + if (centered) + dest_offset -= frame_size / 2; + if (Engine::get_singleton()->get_use_pixel_snap()) { + dest_offset = dest_offset.floor(); + } + + r_dst_rect = Rect2(dest_offset, frame_size); + + if (hflip) + r_dst_rect.size.x = -r_dst_rect.size.x; + if (vflip) + r_dst_rect.size.y = -r_dst_rect.size.y; +} + +void Sprite2D::_notification(int p_what) { + + switch (p_what) { + + case NOTIFICATION_DRAW: { + + if (texture.is_null()) + return; + + RID ci = get_canvas_item(); + + /* + texture->draw(ci,Point2()); + break; + */ + + Rect2 src_rect, dst_rect; + bool filter_clip; + _get_rects(src_rect, dst_rect, filter_clip); + texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, specular, Color(specular_color.r, specular_color.g, specular_color.b, shininess), VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, filter_clip); + + } break; + } +} + +void Sprite2D::set_texture(const Ref &p_texture) { + + if (p_texture == texture) + return; + + if (texture.is_valid()) + texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite2D::_texture_changed)); + + texture = p_texture; + + if (texture.is_valid()) + texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite2D::_texture_changed)); + + update(); + emit_signal("texture_changed"); + item_rect_changed(); + _change_notify("texture"); +} + +void Sprite2D::set_normal_map(const Ref &p_texture) { + + normal_map = p_texture; + update(); +} + +Ref Sprite2D::get_normal_map() const { + + return normal_map; +} + +void Sprite2D::set_specular_map(const Ref &p_texture) { + + specular = p_texture; + update(); +} + +Ref Sprite2D::get_specular_map() const { + + return specular; +} + +void Sprite2D::set_specular_color(const Color &p_color) { + specular_color = p_color; + update(); +} + +Color Sprite2D::get_specular_color() const { + return specular_color; +} + +void Sprite2D::set_shininess(float p_shininess) { + shininess = CLAMP(p_shininess, 0.0, 1.0); + update(); +} + +float Sprite2D::get_shininess() const { + return shininess; +} + +Ref Sprite2D::get_texture() const { + + return texture; +} + +void Sprite2D::set_centered(bool p_center) { + + centered = p_center; + update(); + item_rect_changed(); +} + +bool Sprite2D::is_centered() const { + + return centered; +} + +void Sprite2D::set_offset(const Point2 &p_offset) { + + offset = p_offset; + update(); + item_rect_changed(); + _change_notify("offset"); +} +Point2 Sprite2D::get_offset() const { + + return offset; +} + +void Sprite2D::set_flip_h(bool p_flip) { + + hflip = p_flip; + update(); +} +bool Sprite2D::is_flipped_h() const { + + return hflip; +} + +void Sprite2D::set_flip_v(bool p_flip) { + + vflip = p_flip; + update(); +} +bool Sprite2D::is_flipped_v() const { + + return vflip; +} + +void Sprite2D::set_region(bool p_region) { + + if (p_region == region) + return; + + region = p_region; + update(); +} + +bool Sprite2D::is_region() const { + + return region; +} + +void Sprite2D::set_region_rect(const Rect2 &p_region_rect) { + + if (region_rect == p_region_rect) + return; + + region_rect = p_region_rect; + + if (region) + item_rect_changed(); + + _change_notify("region_rect"); +} + +Rect2 Sprite2D::get_region_rect() const { + + return region_rect; +} + +void Sprite2D::set_region_filter_clip(bool p_enable) { + region_filter_clip = p_enable; + update(); +} + +bool Sprite2D::is_region_filter_clip_enabled() const { + return region_filter_clip; +} + +void Sprite2D::set_frame(int p_frame) { + + ERR_FAIL_INDEX(p_frame, vframes * hframes); + + if (frame != p_frame) + item_rect_changed(); + + frame = p_frame; + + _change_notify("frame"); + _change_notify("frame_coords"); + emit_signal(SceneStringNames::get_singleton()->frame_changed); +} + +int Sprite2D::get_frame() const { + + return frame; +} + +void Sprite2D::set_frame_coords(const Vector2 &p_coord) { + ERR_FAIL_INDEX(int(p_coord.x), hframes); + ERR_FAIL_INDEX(int(p_coord.y), vframes); + + set_frame(int(p_coord.y) * hframes + int(p_coord.x)); +} + +Vector2 Sprite2D::get_frame_coords() const { + return Vector2(frame % hframes, frame / hframes); +} + +void Sprite2D::set_vframes(int p_amount) { + + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1."); + vframes = p_amount; + update(); + item_rect_changed(); + _change_notify(); +} +int Sprite2D::get_vframes() const { + + return vframes; +} + +void Sprite2D::set_hframes(int p_amount) { + + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1."); + hframes = p_amount; + update(); + item_rect_changed(); + _change_notify(); +} +int Sprite2D::get_hframes() const { + + return hframes; +} + +bool Sprite2D::is_pixel_opaque(const Point2 &p_point) const { + + if (texture.is_null()) + return false; + + if (texture->get_size().width == 0 || texture->get_size().height == 0) + return false; + + Rect2 src_rect, dst_rect; + bool filter_clip; + _get_rects(src_rect, dst_rect, filter_clip); + dst_rect.size = dst_rect.size.abs(); + + if (!dst_rect.has_point(p_point)) + return false; + + Vector2 q = (p_point - dst_rect.position) / dst_rect.size; + if (hflip) + q.x = 1.0f - q.x; + if (vflip) + q.y = 1.0f - q.y; + q = q * src_rect.size + src_rect.position; +#ifndef _MSC_VER +#warning this need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that) +#endif + bool is_repeat = false; + bool is_mirrored_repeat = false; + if (is_repeat) { + int mirror_x = 0; + int mirror_y = 0; + if (is_mirrored_repeat) { + mirror_x = (int)(q.x / texture->get_size().width); + mirror_y = (int)(q.y / texture->get_size().height); + } + q.x = Math::fmod(q.x, texture->get_size().width); + q.y = Math::fmod(q.y, texture->get_size().height); + if (mirror_x % 2 == 1) { + q.x = texture->get_size().width - q.x - 1; + } + if (mirror_y % 2 == 1) { + q.y = texture->get_size().height - q.y - 1; + } + } else { + q.x = MIN(q.x, texture->get_size().width - 1); + q.y = MIN(q.y, texture->get_size().height - 1); + } + + return texture->is_pixel_opaque((int)q.x, (int)q.y); +} + +Rect2 Sprite2D::get_rect() const { + + if (texture.is_null()) + return Rect2(0, 0, 1, 1); + + Size2i s; + + if (region) { + s = region_rect.size; + } else { + s = texture->get_size(); + } + + s = s / Point2(hframes, vframes); + + Point2 ofs = offset; + if (centered) + ofs -= Size2(s) / 2; + + if (s == Size2(0, 0)) + s = Size2(1, 1); + + return Rect2(ofs, s); +} + +void Sprite2D::_validate_property(PropertyInfo &property) const { + + if (property.name == "frame") { + property.hint = PROPERTY_HINT_RANGE; + property.hint_string = "0," + itos(vframes * hframes - 1) + ",1"; + property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; + } + + if (property.name == "frame_coords") { + property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; + } +} + +void Sprite2D::_texture_changed() { + + // Changes to the texture need to trigger an update to make + // the editor redraw the sprite with the updated texture. + if (texture.is_valid()) { + update(); + } +} + +void Sprite2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite2D::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &Sprite2D::get_texture); + + ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &Sprite2D::set_normal_map); + ClassDB::bind_method(D_METHOD("get_normal_map"), &Sprite2D::get_normal_map); + + ClassDB::bind_method(D_METHOD("set_specular_map", "specular_map"), &Sprite2D::set_specular_map); + ClassDB::bind_method(D_METHOD("get_specular_map"), &Sprite2D::get_specular_map); + + ClassDB::bind_method(D_METHOD("set_specular_color", "specular_color"), &Sprite2D::set_specular_color); + ClassDB::bind_method(D_METHOD("get_specular_color"), &Sprite2D::get_specular_color); + + ClassDB::bind_method(D_METHOD("set_shininess", "shininess"), &Sprite2D::set_shininess); + ClassDB::bind_method(D_METHOD("get_shininess"), &Sprite2D::get_shininess); + + ClassDB::bind_method(D_METHOD("set_centered", "centered"), &Sprite2D::set_centered); + ClassDB::bind_method(D_METHOD("is_centered"), &Sprite2D::is_centered); + + ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Sprite2D::set_offset); + ClassDB::bind_method(D_METHOD("get_offset"), &Sprite2D::get_offset); + + ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &Sprite2D::set_flip_h); + ClassDB::bind_method(D_METHOD("is_flipped_h"), &Sprite2D::is_flipped_h); + + ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &Sprite2D::set_flip_v); + ClassDB::bind_method(D_METHOD("is_flipped_v"), &Sprite2D::is_flipped_v); + + ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite2D::set_region); + ClassDB::bind_method(D_METHOD("is_region"), &Sprite2D::is_region); + + ClassDB::bind_method(D_METHOD("is_pixel_opaque", "pos"), &Sprite2D::is_pixel_opaque); + + ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite2D::set_region_rect); + ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite2D::get_region_rect); + + ClassDB::bind_method(D_METHOD("set_region_filter_clip", "enabled"), &Sprite2D::set_region_filter_clip); + ClassDB::bind_method(D_METHOD("is_region_filter_clip_enabled"), &Sprite2D::is_region_filter_clip_enabled); + + ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite2D::set_frame); + ClassDB::bind_method(D_METHOD("get_frame"), &Sprite2D::get_frame); + + ClassDB::bind_method(D_METHOD("set_frame_coords", "coords"), &Sprite2D::set_frame_coords); + ClassDB::bind_method(D_METHOD("get_frame_coords"), &Sprite2D::get_frame_coords); + + ClassDB::bind_method(D_METHOD("set_vframes", "vframes"), &Sprite2D::set_vframes); + ClassDB::bind_method(D_METHOD("get_vframes"), &Sprite2D::get_vframes); + + ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite2D::set_hframes); + ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite2D::get_hframes); + + ClassDB::bind_method(D_METHOD("get_rect"), &Sprite2D::get_rect); + + ADD_SIGNAL(MethodInfo("frame_changed")); + ADD_SIGNAL(MethodInfo("texture_changed")); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); + ADD_GROUP("Lighting", ""); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_map", "get_specular_map"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_shininess", "get_shininess"); + ADD_GROUP("Offset", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v"); + ADD_GROUP("Animation", ""); + ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); + + ADD_GROUP("Region", "region_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region"); + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_filter_clip"), "set_region_filter_clip", "is_region_filter_clip_enabled"); +} + +Sprite2D::Sprite2D() { + + centered = true; + hflip = false; + vflip = false; + region = false; + region_filter_clip = false; + shininess = 1.0; + specular_color = Color(1, 1, 1, 1); + + frame = 0; + + vframes = 1; + hframes = 1; +} + +Sprite2D::~Sprite2D() { +} diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h new file mode 100644 index 0000000000..599a9e937e --- /dev/null +++ b/scene/2d/sprite_2d.h @@ -0,0 +1,143 @@ +/*************************************************************************/ +/* sprite_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_2D_H +#define SPRITE_2D_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/texture.h" + +class Sprite2D : public Node2D { + + GDCLASS(Sprite2D, Node2D); + + Ref texture; + Ref normal_map; + Ref specular; + Color specular_color; + float shininess; + + bool centered; + Point2 offset; + + bool hflip; + bool vflip; + bool region; + Rect2 region_rect; + bool region_filter_clip; + + int frame; + + int vframes; + int hframes; + + void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const; + + void _texture_changed(); + +protected: + void _notification(int p_what); + + static void _bind_methods(); + + virtual void _validate_property(PropertyInfo &property) const; + +public: +#ifdef TOOLS_ENABLED + virtual Dictionary _edit_get_state() const; + virtual void _edit_set_state(const Dictionary &p_state); + + virtual void _edit_set_pivot(const Point2 &p_pivot); + virtual Point2 _edit_get_pivot() const; + virtual bool _edit_use_pivot() const; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; + + virtual Rect2 _edit_get_rect() const; + virtual bool _edit_use_rect() const; +#endif + + bool is_pixel_opaque(const Point2 &p_point) const; + + void set_texture(const Ref &p_texture); + Ref get_texture() const; + + void set_normal_map(const Ref &p_texture); + Ref get_normal_map() const; + + void set_specular_map(const Ref &p_texture); + Ref get_specular_map() const; + + void set_specular_color(const Color &p_color); + Color get_specular_color() const; + + void set_shininess(float p_shininess); + float get_shininess() const; + + void set_centered(bool p_center); + bool is_centered() const; + + void set_offset(const Point2 &p_offset); + Point2 get_offset() const; + + void set_flip_h(bool p_flip); + bool is_flipped_h() const; + + void set_flip_v(bool p_flip); + bool is_flipped_v() const; + + void set_region(bool p_region); + bool is_region() const; + + void set_region_filter_clip(bool p_enable); + bool is_region_filter_clip_enabled() const; + + void set_region_rect(const Rect2 &p_region_rect); + Rect2 get_region_rect() const; + + void set_frame(int p_frame); + int get_frame() const; + + void set_frame_coords(const Vector2 &p_coord); + Vector2 get_frame_coords() const; + + void set_vframes(int p_amount); + int get_vframes() const; + + void set_hframes(int p_amount); + int get_hframes() const; + + Rect2 get_rect() const; + virtual Rect2 get_anchorable_rect() const; + + Sprite2D(); + ~Sprite2D(); +}; + +#endif // SPRITE_H diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index 65dabb92b1..6c1d7c3749 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -32,7 +32,7 @@ #include "core/engine.h" #include "particles_2d.h" -#include "scene/2d/animated_sprite.h" +#include "scene/2d/animated_sprite_2d.h" #include "scene/2d/physics_body_2d.h" #include "scene/animation/animation_player.h" #include "scene/main/window.h" @@ -205,7 +205,7 @@ void VisibilityEnabler2D::_find_nodes(Node *p_node) { } { - AnimatedSprite *as = Object::cast_to(p_node); + AnimatedSprite2D *as = Object::cast_to(p_node); if (as) { add = true; } @@ -292,7 +292,7 @@ void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) { } if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) { - AnimatedSprite *as = Object::cast_to(p_node); + AnimatedSprite2D *as = Object::cast_to(p_node); if (as) { -- cgit v1.2.3