From eaae4b6408361eb34363adcb22a08046f43147f4 Mon Sep 17 00:00:00 2001
From: Juan Linietsky <reduzio@gmail.com>
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<Texture2D> 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<Texture2D> 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<Texture2D> &p_frame, int p_at_pos) {
-
-	Map<StringName, Anim>::Element *E = animations.find(p_anim);
-	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-
-	if (p_at_pos >= 0 && p_at_pos < E->get().frames.size())
-		E->get().frames.insert(p_at_pos, p_frame);
-	else
-		E->get().frames.push_back(p_frame);
-
-	emit_changed();
-}
-
-int SpriteFrames::get_frame_count(const StringName &p_anim) const {
-	const Map<StringName, Anim>::Element *E = animations.find(p_anim);
-	ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
-
-	return E->get().frames.size();
-}
-
-void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
-
-	Map<StringName, Anim>::Element *E = animations.find(p_anim);
-	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-
-	E->get().frames.remove(p_idx);
-	emit_changed();
-}
-void SpriteFrames::clear(const StringName &p_anim) {
-
-	Map<StringName, Anim>::Element *E = animations.find(p_anim);
-	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-
-	E->get().frames.clear();
-	emit_changed();
-}
-
-void SpriteFrames::clear_all() {
-
-	animations.clear();
-	add_animation("default");
-}
-
-void SpriteFrames::add_animation(const StringName &p_anim) {
-
-	ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'.");
-
-	animations[p_anim] = Anim();
-	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<String> SpriteFrames::_get_animation_list() const {
-
-	Vector<String> ret;
-	List<StringName> al;
-	get_animation_list(&al);
-	for (List<StringName>::Element *E = al.front(); E; E = E->next()) {
-
-		ret.push_back(E->get());
-	}
-
-	return ret;
-}
-
-void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
-
-	for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
-		r_animations->push_back(E->key());
-	}
-}
-
-Vector<String> SpriteFrames::get_animation_names() const {
-
-	Vector<String> names;
-	for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
-		names.push_back(E->key());
-	}
-	names.sort();
-	return names;
-}
-
-void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) {
-
-	ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ").");
-	Map<StringName, Anim>::Element *E = animations.find(p_anim);
-	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-	E->get().speed = p_fps;
-}
-float SpriteFrames::get_animation_speed(const StringName &p_anim) const {
-
-	const Map<StringName, Anim>::Element *E = animations.find(p_anim);
-	ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
-	return E->get().speed;
-}
-
-void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) {
-	Map<StringName, Anim>::Element *E = animations.find(p_anim);
-	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-	E->get().loop = p_loop;
-}
-bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
-	const Map<StringName, Anim>::Element *E = animations.find(p_anim);
-	ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist.");
-	return E->get().loop;
-}
-
-void SpriteFrames::_set_frames(const Array &p_frames) {
-
-	clear_all();
-	Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default);
-	ERR_FAIL_COND(!E);
-
-	E->get().frames.resize(p_frames.size());
-	for (int i = 0; i < E->get().frames.size(); i++)
-		E->get().frames.write[i] = p_frames[i];
-}
-Array SpriteFrames::_get_frames() const {
-
-	return Array();
-}
-
-Array SpriteFrames::_get_animations() const {
-
-	Array anims;
-	for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
-		Dictionary d;
-		d["name"] = E->key();
-		d["speed"] = E->get().speed;
-		d["loop"] = E->get().loop;
-		Array frames;
-		for (int i = 0; i < E->get().frames.size(); i++) {
-			frames.push_back(E->get().frames[i]);
-		}
-		d["frames"] = frames;
-		anims.push_back(d);
-	}
-
-	return anims;
-}
-void SpriteFrames::_set_animations(const Array &p_animations) {
-
-	animations.clear();
-	for (int i = 0; i < p_animations.size(); i++) {
-
-		Dictionary d = p_animations[i];
-
-		ERR_CONTINUE(!d.has("name"));
-		ERR_CONTINUE(!d.has("speed"));
-		ERR_CONTINUE(!d.has("loop"));
-		ERR_CONTINUE(!d.has("frames"));
-
-		Anim anim;
-		anim.speed = d["speed"];
-		anim.loop = d["loop"];
-		Array frames = d["frames"];
-		for (int j = 0; j < frames.size(); j++) {
-
-			RES res = frames[j];
-			anim.frames.push_back(res);
-		}
-
-		animations[d["name"]] = anim;
-	}
-}
-
-void SpriteFrames::_bind_methods() {
-
-	ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation);
-	ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation);
-	ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation);
-	ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation);
-
-	ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names);
-
-	ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed);
-	ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed);
-
-	ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop);
-	ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop);
-
-	ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1));
-	ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count);
-	ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame);
-	ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame);
-	ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame);
-	ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear);
-	ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all);
-
-	ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames);
-	ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames);
-
-	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility
-
-	ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
-	ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
-
-	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
-}
-
-SpriteFrames::SpriteFrames() {
-
-	add_animation(SceneStringNames::get_singleton()->_default);
-}
-
-void AnimatedSprite::_validate_property(PropertyInfo &property) const {
-
-	if (!frames.is_valid())
-		return;
-	if (property.name == "animation") {
-
-		property.hint = PROPERTY_HINT_ENUM;
-		List<StringName> names;
-		frames->get_animation_list(&names);
-		names.sort_custom<StringName::AlphCompare>();
-
-		bool current_found = false;
-
-		for (List<StringName>::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<Texture2D> texture = frames->get_frame(animation, frame);
-			if (texture.is_null())
-				return;
-
-			Ref<Texture2D> normal = frames->get_normal_frame(animation, frame);
-			Ref<Texture2D> 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<SpriteFrames> &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<SpriteFrames> 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<Ref<Texture2D>> frames;
-
-		Anim() {
-			loop = true;
-			speed = 5;
-		}
-
-		StringName normal_name;
-		StringName specular_name;
-	};
-
-	Color specular_color;
-	float shininess;
-
-	Map<StringName, Anim> animations;
-
-	Array _get_frames() const;
-	void _set_frames(const Array &p_frames);
-
-	Array _get_animations() const;
-	void _set_animations(const Array &p_animations);
-
-	Vector<String> _get_animation_list() const;
-
-protected:
-	static void _bind_methods();
-
-public:
-	void add_animation(const StringName &p_anim);
-	bool has_animation(const StringName &p_anim) const;
-	void remove_animation(const StringName &p_anim);
-	void rename_animation(const StringName &p_prev, const StringName &p_next);
-
-	void get_animation_list(List<StringName> *r_animations) const;
-	Vector<String> get_animation_names() const;
-
-	void set_animation_speed(const StringName &p_anim, float p_fps);
-	float get_animation_speed(const StringName &p_anim) const;
-
-	void set_animation_loop(const StringName &p_anim, bool p_loop);
-	bool get_animation_loop(const StringName &p_anim) const;
-
-	void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1);
-	int get_frame_count(const StringName &p_anim) const;
-	_FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const {
-
-		const Map<StringName, Anim>::Element *E = animations.find(p_anim);
-		ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
-		ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
-		if (p_idx >= E->get().frames.size())
-			return Ref<Texture2D>();
-
-		return E->get().frames[p_idx];
-	}
-
-	_FORCE_INLINE_ Ref<Texture2D> get_normal_frame(const StringName &p_anim, int p_idx) const {
-
-		const Map<StringName, Anim>::Element *E = animations.find(p_anim);
-		ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
-		ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
-
-		const Map<StringName, Anim>::Element *EN = animations.find(E->get().normal_name);
-
-		if (!EN || p_idx >= EN->get().frames.size())
-			return Ref<Texture2D>();
-
-		return EN->get().frames[p_idx];
-	}
-
-	_FORCE_INLINE_ Ref<Texture2D> get_specular_frame(const StringName &p_anim, int p_idx) const {
-
-		const Map<StringName, Anim>::Element *E = animations.find(p_anim);
-		ERR_FAIL_COND_V(!E, Ref<Texture2D>());
-		ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
-
-		const Map<StringName, Anim>::Element *EN = animations.find(E->get().specular_name);
-
-		if (!EN || p_idx >= EN->get().frames.size())
-			return Ref<Texture2D>();
-
-		return EN->get().frames[p_idx];
-	}
-
-	void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) {
-		Map<StringName, Anim>::Element *E = animations.find(p_anim);
-		ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
-		ERR_FAIL_COND(p_idx < 0);
-		if (p_idx >= E->get().frames.size())
-			return;
-		E->get().frames.write[p_idx] = p_frame;
-	}
-	void remove_frame(const StringName &p_anim, int p_idx);
-	void clear(const StringName &p_anim);
-	void clear_all();
-
-	SpriteFrames();
-};
-
-class AnimatedSprite : public Node2D {
-
-	GDCLASS(AnimatedSprite, Node2D);
-
-	Ref<SpriteFrames> 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<SpriteFrames> &p_frames);
-	Ref<SpriteFrames> 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<Texture2D> 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<Texture2D> 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<Texture2D> &p_frame, int p_at_pos) {
+
+	Map<StringName, Anim>::Element *E = animations.find(p_anim);
+	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+	if (p_at_pos >= 0 && p_at_pos < E->get().frames.size())
+		E->get().frames.insert(p_at_pos, p_frame);
+	else
+		E->get().frames.push_back(p_frame);
+
+	emit_changed();
+}
+
+int SpriteFrames::get_frame_count(const StringName &p_anim) const {
+	const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+	ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+	return E->get().frames.size();
+}
+
+void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
+
+	Map<StringName, Anim>::Element *E = animations.find(p_anim);
+	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+	E->get().frames.remove(p_idx);
+	emit_changed();
+}
+void SpriteFrames::clear(const StringName &p_anim) {
+
+	Map<StringName, Anim>::Element *E = animations.find(p_anim);
+	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+
+	E->get().frames.clear();
+	emit_changed();
+}
+
+void SpriteFrames::clear_all() {
+
+	animations.clear();
+	add_animation("default");
+}
+
+void SpriteFrames::add_animation(const StringName &p_anim) {
+
+	ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'.");
+
+	animations[p_anim] = Anim();
+	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<String> SpriteFrames::_get_animation_list() const {
+
+	Vector<String> ret;
+	List<StringName> al;
+	get_animation_list(&al);
+	for (List<StringName>::Element *E = al.front(); E; E = E->next()) {
+
+		ret.push_back(E->get());
+	}
+
+	return ret;
+}
+
+void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
+
+	for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+		r_animations->push_back(E->key());
+	}
+}
+
+Vector<String> SpriteFrames::get_animation_names() const {
+
+	Vector<String> names;
+	for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+		names.push_back(E->key());
+	}
+	names.sort();
+	return names;
+}
+
+void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) {
+
+	ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ").");
+	Map<StringName, Anim>::Element *E = animations.find(p_anim);
+	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+	E->get().speed = p_fps;
+}
+float SpriteFrames::get_animation_speed(const StringName &p_anim) const {
+
+	const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+	ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
+	return E->get().speed;
+}
+
+void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) {
+	Map<StringName, Anim>::Element *E = animations.find(p_anim);
+	ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+	E->get().loop = p_loop;
+}
+bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
+	const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+	ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist.");
+	return E->get().loop;
+}
+
+void SpriteFrames::_set_frames(const Array &p_frames) {
+
+	clear_all();
+	Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default);
+	ERR_FAIL_COND(!E);
+
+	E->get().frames.resize(p_frames.size());
+	for (int i = 0; i < E->get().frames.size(); i++)
+		E->get().frames.write[i] = p_frames[i];
+}
+Array SpriteFrames::_get_frames() const {
+
+	return Array();
+}
+
+Array SpriteFrames::_get_animations() const {
+
+	Array anims;
+	for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
+		Dictionary d;
+		d["name"] = E->key();
+		d["speed"] = E->get().speed;
+		d["loop"] = E->get().loop;
+		Array frames;
+		for (int i = 0; i < E->get().frames.size(); i++) {
+			frames.push_back(E->get().frames[i]);
+		}
+		d["frames"] = frames;
+		anims.push_back(d);
+	}
+
+	return anims;
+}
+void SpriteFrames::_set_animations(const Array &p_animations) {
+
+	animations.clear();
+	for (int i = 0; i < p_animations.size(); i++) {
+
+		Dictionary d = p_animations[i];
+
+		ERR_CONTINUE(!d.has("name"));
+		ERR_CONTINUE(!d.has("speed"));
+		ERR_CONTINUE(!d.has("loop"));
+		ERR_CONTINUE(!d.has("frames"));
+
+		Anim anim;
+		anim.speed = d["speed"];
+		anim.loop = d["loop"];
+		Array frames = d["frames"];
+		for (int j = 0; j < frames.size(); j++) {
+
+			RES res = frames[j];
+			anim.frames.push_back(res);
+		}
+
+		animations[d["name"]] = anim;
+	}
+}
+
+void SpriteFrames::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation);
+	ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation);
+	ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation);
+	ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation);
+
+	ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names);
+
+	ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed);
+	ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed);
+
+	ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop);
+	ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop);
+
+	ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1));
+	ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count);
+	ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame);
+	ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame);
+	ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame);
+	ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear);
+	ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all);
+
+	ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames);
+	ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames);
+
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility
+
+	ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
+	ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
+
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
+}
+
+SpriteFrames::SpriteFrames() {
+
+	add_animation(SceneStringNames::get_singleton()->_default);
+}
+
+void AnimatedSprite2D::_validate_property(PropertyInfo &property) const {
+
+	if (!frames.is_valid())
+		return;
+	if (property.name == "animation") {
+
+		property.hint = PROPERTY_HINT_ENUM;
+		List<StringName> names;
+		frames->get_animation_list(&names);
+		names.sort_custom<StringName::AlphCompare>();
+
+		bool current_found = false;
+
+		for (List<StringName>::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<Texture2D> texture = frames->get_frame(animation, frame);
+			if (texture.is_null())
+				return;
+
+			Ref<Texture2D> normal = frames->get_normal_frame(animation, frame);
+			Ref<Texture2D> 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<SpriteFrames> &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<SpriteFrames> 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<Ref<Texture2D>> frames;
+
+		Anim() {
+			loop = true;
+			speed = 5;
+		}
+
+		StringName normal_name;
+		StringName specular_name;
+	};
+
+	Color specular_color;
+	float shininess;
+
+	Map<StringName, Anim> animations;
+
+	Array _get_frames() const;
+	void _set_frames(const Array &p_frames);
+
+	Array _get_animations() const;
+	void _set_animations(const Array &p_animations);
+
+	Vector<String> _get_animation_list() const;
+
+protected:
+	static void _bind_methods();
+
+public:
+	void add_animation(const StringName &p_anim);
+	bool has_animation(const StringName &p_anim) const;
+	void remove_animation(const StringName &p_anim);
+	void rename_animation(const StringName &p_prev, const StringName &p_next);
+
+	void get_animation_list(List<StringName> *r_animations) const;
+	Vector<String> get_animation_names() const;
+
+	void set_animation_speed(const StringName &p_anim, float p_fps);
+	float get_animation_speed(const StringName &p_anim) const;
+
+	void set_animation_loop(const StringName &p_anim, bool p_loop);
+	bool get_animation_loop(const StringName &p_anim) const;
+
+	void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1);
+	int get_frame_count(const StringName &p_anim) const;
+	_FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const {
+
+		const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+		ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
+		ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
+		if (p_idx >= E->get().frames.size())
+			return Ref<Texture2D>();
+
+		return E->get().frames[p_idx];
+	}
+
+	_FORCE_INLINE_ Ref<Texture2D> get_normal_frame(const StringName &p_anim, int p_idx) const {
+
+		const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+		ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
+		ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
+
+		const Map<StringName, Anim>::Element *EN = animations.find(E->get().normal_name);
+
+		if (!EN || p_idx >= EN->get().frames.size())
+			return Ref<Texture2D>();
+
+		return EN->get().frames[p_idx];
+	}
+
+	_FORCE_INLINE_ Ref<Texture2D> get_specular_frame(const StringName &p_anim, int p_idx) const {
+
+		const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+		ERR_FAIL_COND_V(!E, Ref<Texture2D>());
+		ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
+
+		const Map<StringName, Anim>::Element *EN = animations.find(E->get().specular_name);
+
+		if (!EN || p_idx >= EN->get().frames.size())
+			return Ref<Texture2D>();
+
+		return EN->get().frames[p_idx];
+	}
+
+	void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) {
+		Map<StringName, Anim>::Element *E = animations.find(p_anim);
+		ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+		ERR_FAIL_COND(p_idx < 0);
+		if (p_idx >= E->get().frames.size())
+			return;
+		E->get().frames.write[p_idx] = p_frame;
+	}
+	void remove_frame(const StringName &p_anim, int p_idx);
+	void clear(const StringName &p_anim);
+	void clear_all();
+
+	SpriteFrames();
+};
+
+class AnimatedSprite2D : public Node2D {
+
+	GDCLASS(AnimatedSprite2D, Node2D);
+
+	Ref<SpriteFrames> 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<SpriteFrames> &p_frames);
+	Ref<SpriteFrames> 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<Texture2D> &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<Texture2D> &p_texture) {
-
-	normal_map = p_texture;
-	update();
-}
-
-Ref<Texture2D> Sprite::get_normal_map() const {
-
-	return normal_map;
-}
-
-void Sprite::set_specular_map(const Ref<Texture2D> &p_texture) {
-
-	specular = p_texture;
-	update();
-}
-
-Ref<Texture2D> 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<Texture2D> 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<Texture2D> texture;
-	Ref<Texture2D> normal_map;
-	Ref<Texture2D> 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<Texture2D> &p_texture);
-	Ref<Texture2D> get_texture() const;
-
-	void set_normal_map(const Ref<Texture2D> &p_texture);
-	Ref<Texture2D> get_normal_map() const;
-
-	void set_specular_map(const Ref<Texture2D> &p_texture);
-	Ref<Texture2D> 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<Texture2D> &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<Texture2D> &p_texture) {
+
+	normal_map = p_texture;
+	update();
+}
+
+Ref<Texture2D> Sprite2D::get_normal_map() const {
+
+	return normal_map;
+}
+
+void Sprite2D::set_specular_map(const Ref<Texture2D> &p_texture) {
+
+	specular = p_texture;
+	update();
+}
+
+Ref<Texture2D> 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<Texture2D> 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<Texture2D> texture;
+	Ref<Texture2D> normal_map;
+	Ref<Texture2D> 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<Texture2D> &p_texture);
+	Ref<Texture2D> get_texture() const;
+
+	void set_normal_map(const Ref<Texture2D> &p_texture);
+	Ref<Texture2D> get_normal_map() const;
+
+	void set_specular_map(const Ref<Texture2D> &p_texture);
+	Ref<Texture2D> 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<AnimatedSprite>(p_node);
+		AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(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<AnimatedSprite>(p_node);
+		AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node);
 
 		if (as) {
 
-- 
cgit v1.2.3


From d1acbbce7f123c2b5fccdefc6417787dc91b6ced Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= <rverschelde@gmail.com>
Date: Fri, 27 Mar 2020 08:44:44 +0100
Subject: Rename more 2D and 3D nodes to follow convention

Rename editor plugins to match the new node names.
---
 scene/2d/canvas_item.cpp            | 1491 -----------------------------------
 scene/2d/canvas_item.h              |  426 ----------
 scene/2d/cpu_particles_2d.cpp       |    6 +-
 scene/2d/gpu_particles_2d.cpp       |  432 ++++++++++
 scene/2d/gpu_particles_2d.h         |  127 +++
 scene/2d/navigation_2d.h            |    2 +-
 scene/2d/navigation_polygon.cpp     |  582 --------------
 scene/2d/navigation_polygon.h       |  130 ---
 scene/2d/navigation_region_2d.cpp   |  582 ++++++++++++++
 scene/2d/navigation_region_2d.h     |  130 +++
 scene/2d/node_2d.h                  |    2 +-
 scene/2d/particles_2d.cpp           |  432 ----------
 scene/2d/particles_2d.h             |  127 ---
 scene/2d/visibility_notifier_2d.cpp |    6 +-
 14 files changed, 1279 insertions(+), 3196 deletions(-)
 delete mode 100644 scene/2d/canvas_item.cpp
 delete mode 100644 scene/2d/canvas_item.h
 create mode 100644 scene/2d/gpu_particles_2d.cpp
 create mode 100644 scene/2d/gpu_particles_2d.h
 delete mode 100644 scene/2d/navigation_polygon.cpp
 delete mode 100644 scene/2d/navigation_polygon.h
 create mode 100644 scene/2d/navigation_region_2d.cpp
 create mode 100644 scene/2d/navigation_region_2d.h
 delete mode 100644 scene/2d/particles_2d.cpp
 delete mode 100644 scene/2d/particles_2d.h

(limited to 'scene/2d')

diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
deleted file mode 100644
index 7a0fc3352b..0000000000
--- a/scene/2d/canvas_item.cpp
+++ /dev/null
@@ -1,1491 +0,0 @@
-/*************************************************************************/
-/*  canvas_item.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 "canvas_item.h"
-
-#include "core/input/input_filter.h"
-#include "core/message_queue.h"
-#include "core/method_bind_ext.gen.inc"
-#include "scene/main/canvas_layer.h"
-#include "scene/main/viewport.h"
-#include "scene/main/window.h"
-#include "scene/resources/font.h"
-#include "scene/resources/style_box.h"
-#include "scene/resources/texture.h"
-#include "scene/scene_string_names.h"
-#include "servers/visual/visual_server_raster.h"
-#include "servers/visual_server.h"
-
-Mutex CanvasItemMaterial::material_mutex;
-SelfList<CanvasItemMaterial>::List *CanvasItemMaterial::dirty_materials = NULL;
-Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
-CanvasItemMaterial::ShaderNames *CanvasItemMaterial::shader_names = NULL;
-
-void CanvasItemMaterial::init_shaders() {
-
-	dirty_materials = memnew(SelfList<CanvasItemMaterial>::List);
-
-	shader_names = memnew(ShaderNames);
-
-	shader_names->particles_anim_h_frames = "particles_anim_h_frames";
-	shader_names->particles_anim_v_frames = "particles_anim_v_frames";
-	shader_names->particles_anim_loop = "particles_anim_loop";
-}
-
-void CanvasItemMaterial::finish_shaders() {
-
-	memdelete(dirty_materials);
-	memdelete(shader_names);
-	dirty_materials = NULL;
-}
-
-void CanvasItemMaterial::_update_shader() {
-
-	dirty_materials->remove(&element);
-
-	MaterialKey mk = _compute_key();
-	if (mk.key == current_key.key)
-		return; //no update required in the end
-
-	if (shader_map.has(current_key)) {
-		shader_map[current_key].users--;
-		if (shader_map[current_key].users == 0) {
-			//deallocate shader, as it's no longer in use
-			VS::get_singleton()->free(shader_map[current_key].shader);
-			shader_map.erase(current_key);
-		}
-	}
-
-	current_key = mk;
-
-	if (shader_map.has(mk)) {
-
-		VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
-		shader_map[mk].users++;
-		return;
-	}
-
-	//must create a shader!
-
-	String code = "shader_type canvas_item;\nrender_mode ";
-	switch (blend_mode) {
-		case BLEND_MODE_MIX: code += "blend_mix"; break;
-		case BLEND_MODE_ADD: code += "blend_add"; break;
-		case BLEND_MODE_SUB: code += "blend_sub"; break;
-		case BLEND_MODE_MUL: code += "blend_mul"; break;
-		case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break;
-		case BLEND_MODE_DISABLED: code += "blend_disabled"; break;
-	}
-
-	switch (light_mode) {
-		case LIGHT_MODE_NORMAL: break;
-		case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
-		case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
-	}
-
-	code += ";\n";
-
-	if (particles_animation) {
-
-		code += "uniform int particles_anim_h_frames;\n";
-		code += "uniform int particles_anim_v_frames;\n";
-		code += "uniform bool particles_anim_loop;\n";
-
-		code += "void vertex() {\n";
-
-		code += "\tfloat h_frames = float(particles_anim_h_frames);\n";
-		code += "\tfloat v_frames = float(particles_anim_v_frames);\n";
-
-		code += "\tVERTEX.xy /= vec2(h_frames, v_frames);\n";
-
-		code += "\tfloat particle_total_frames = float(particles_anim_h_frames * particles_anim_v_frames);\n";
-		code += "\tfloat particle_frame = floor(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
-		code += "\tif (!particles_anim_loop) {\n";
-		code += "\t\tparticle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
-		code += "\t} else {\n";
-		code += "\t\tparticle_frame = mod(particle_frame, particle_total_frames);\n";
-		code += "\t}";
-		code += "\tUV /= vec2(h_frames, v_frames);\n";
-		code += "\tUV += vec2(mod(particle_frame, h_frames) / h_frames, floor(particle_frame / h_frames) / v_frames);\n";
-		code += "}\n";
-	}
-
-	ShaderData shader_data;
-	shader_data.shader = VS::get_singleton()->shader_create();
-	shader_data.users = 1;
-
-	VS::get_singleton()->shader_set_code(shader_data.shader, code);
-
-	shader_map[mk] = shader_data;
-
-	VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
-}
-
-void CanvasItemMaterial::flush_changes() {
-
-	MutexLock lock(material_mutex);
-
-	while (dirty_materials->first()) {
-
-		dirty_materials->first()->self()->_update_shader();
-	}
-}
-
-void CanvasItemMaterial::_queue_shader_change() {
-
-	MutexLock lock(material_mutex);
-
-	if (!element.in_list()) {
-		dirty_materials->add(&element);
-	}
-}
-
-bool CanvasItemMaterial::_is_shader_dirty() const {
-
-	MutexLock lock(material_mutex);
-
-	return element.in_list();
-}
-void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) {
-
-	blend_mode = p_blend_mode;
-	_queue_shader_change();
-}
-
-CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const {
-	return blend_mode;
-}
-
-void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) {
-
-	light_mode = p_light_mode;
-	_queue_shader_change();
-}
-
-CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
-
-	return light_mode;
-}
-
-void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) {
-	particles_animation = p_particles_anim;
-	_queue_shader_change();
-	_change_notify();
-}
-
-bool CanvasItemMaterial::get_particles_animation() const {
-	return particles_animation;
-}
-
-void CanvasItemMaterial::set_particles_anim_h_frames(int p_frames) {
-
-	particles_anim_h_frames = p_frames;
-	VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
-}
-
-int CanvasItemMaterial::get_particles_anim_h_frames() const {
-
-	return particles_anim_h_frames;
-}
-void CanvasItemMaterial::set_particles_anim_v_frames(int p_frames) {
-
-	particles_anim_v_frames = p_frames;
-	VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
-}
-
-int CanvasItemMaterial::get_particles_anim_v_frames() const {
-
-	return particles_anim_v_frames;
-}
-
-void CanvasItemMaterial::set_particles_anim_loop(bool p_loop) {
-
-	particles_anim_loop = p_loop;
-	VS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
-}
-
-bool CanvasItemMaterial::get_particles_anim_loop() const {
-
-	return particles_anim_loop;
-}
-
-void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
-	if (property.name.begins_with("particles_anim_") && !particles_animation) {
-		property.usage = 0;
-	}
-}
-
-RID CanvasItemMaterial::get_shader_rid() const {
-
-	ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
-	return shader_map[current_key].shader;
-}
-
-Shader::Mode CanvasItemMaterial::get_shader_mode() const {
-
-	return Shader::MODE_CANVAS_ITEM;
-}
-
-void CanvasItemMaterial::_bind_methods() {
-
-	ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode);
-	ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode);
-
-	ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode);
-	ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode);
-
-	ClassDB::bind_method(D_METHOD("set_particles_animation", "particles_anim"), &CanvasItemMaterial::set_particles_animation);
-	ClassDB::bind_method(D_METHOD("get_particles_animation"), &CanvasItemMaterial::get_particles_animation);
-
-	ClassDB::bind_method(D_METHOD("set_particles_anim_h_frames", "frames"), &CanvasItemMaterial::set_particles_anim_h_frames);
-	ClassDB::bind_method(D_METHOD("get_particles_anim_h_frames"), &CanvasItemMaterial::get_particles_anim_h_frames);
-
-	ClassDB::bind_method(D_METHOD("set_particles_anim_v_frames", "frames"), &CanvasItemMaterial::set_particles_anim_v_frames);
-	ClassDB::bind_method(D_METHOD("get_particles_anim_v_frames"), &CanvasItemMaterial::get_particles_anim_v_frames);
-
-	ClassDB::bind_method(D_METHOD("set_particles_anim_loop", "loop"), &CanvasItemMaterial::set_particles_anim_loop);
-	ClassDB::bind_method(D_METHOD("get_particles_anim_loop"), &CanvasItemMaterial::get_particles_anim_loop);
-
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_animation"), "set_particles_animation", "get_particles_animation");
-
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_h_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_h_frames", "get_particles_anim_h_frames");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "particles_anim_v_frames", PROPERTY_HINT_RANGE, "1,128,1"), "set_particles_anim_v_frames", "get_particles_anim_v_frames");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "particles_anim_loop"), "set_particles_anim_loop", "get_particles_anim_loop");
-
-	BIND_ENUM_CONSTANT(BLEND_MODE_MIX);
-	BIND_ENUM_CONSTANT(BLEND_MODE_ADD);
-	BIND_ENUM_CONSTANT(BLEND_MODE_SUB);
-	BIND_ENUM_CONSTANT(BLEND_MODE_MUL);
-	BIND_ENUM_CONSTANT(BLEND_MODE_PREMULT_ALPHA);
-
-	BIND_ENUM_CONSTANT(LIGHT_MODE_NORMAL);
-	BIND_ENUM_CONSTANT(LIGHT_MODE_UNSHADED);
-	BIND_ENUM_CONSTANT(LIGHT_MODE_LIGHT_ONLY);
-}
-
-CanvasItemMaterial::CanvasItemMaterial() :
-		element(this) {
-
-	blend_mode = BLEND_MODE_MIX;
-	light_mode = LIGHT_MODE_NORMAL;
-	particles_animation = false;
-
-	set_particles_anim_h_frames(1);
-	set_particles_anim_v_frames(1);
-	set_particles_anim_loop(false);
-
-	current_key.key = 0;
-	current_key.invalid_key = 1;
-	_queue_shader_change();
-}
-
-CanvasItemMaterial::~CanvasItemMaterial() {
-
-	MutexLock lock(material_mutex);
-
-	if (shader_map.has(current_key)) {
-		shader_map[current_key].users--;
-		if (shader_map[current_key].users == 0) {
-			//deallocate shader, as it's no longer in use
-			VS::get_singleton()->free(shader_map[current_key].shader);
-			shader_map.erase(current_key);
-		}
-
-		VS::get_singleton()->material_set_shader(_get_material(), RID());
-	}
-}
-
-///////////////////////////////////////////////////////////////////
-#ifdef TOOLS_ENABLED
-bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
-	if (_edit_use_rect()) {
-		return _edit_get_rect().has_point(p_point);
-	} else {
-		return p_point.length() < p_tolerance;
-	}
-}
-
-Transform2D CanvasItem::_edit_get_transform() const {
-	return Transform2D(_edit_get_rotation(), _edit_get_position() + _edit_get_pivot());
-}
-#endif
-
-bool CanvasItem::is_visible_in_tree() const {
-
-	if (!is_inside_tree())
-		return false;
-
-	const CanvasItem *p = this;
-
-	while (p) {
-		if (!p->visible)
-			return false;
-		if (p->window && !p->window->is_visible()) {
-			return false;
-		}
-		p = p->get_parent_item();
-	}
-
-	return true;
-}
-
-void CanvasItem::_propagate_visibility_changed(bool p_visible) {
-
-	if (p_visible && first_draw) { //avoid propagating it twice
-		first_draw = false;
-	}
-	notification(NOTIFICATION_VISIBILITY_CHANGED);
-
-	if (p_visible)
-		update(); //todo optimize
-	else
-		emit_signal(SceneStringNames::get_singleton()->hide);
-	_block();
-
-	for (int i = 0; i < get_child_count(); i++) {
-
-		CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
-
-		if (c && c->visible) //should the toplevels stop propagation? i think so but..
-			c->_propagate_visibility_changed(p_visible);
-	}
-
-	_unblock();
-}
-
-void CanvasItem::show() {
-
-	if (visible)
-		return;
-
-	visible = true;
-	VisualServer::get_singleton()->canvas_item_set_visible(canvas_item, true);
-
-	if (!is_inside_tree())
-		return;
-
-	_propagate_visibility_changed(true);
-	_change_notify("visible");
-}
-
-void CanvasItem::hide() {
-
-	if (!visible)
-		return;
-
-	visible = false;
-	VisualServer::get_singleton()->canvas_item_set_visible(canvas_item, false);
-
-	if (!is_inside_tree())
-		return;
-
-	_propagate_visibility_changed(false);
-	_change_notify("visible");
-}
-
-CanvasItem *CanvasItem::current_item_drawn = NULL;
-CanvasItem *CanvasItem::get_current_item_drawn() {
-	return current_item_drawn;
-}
-
-void CanvasItem::_update_callback() {
-
-	if (!is_inside_tree()) {
-		pending_update = false;
-		return;
-	}
-
-	VisualServer::get_singleton()->canvas_item_clear(get_canvas_item());
-	//todo updating = true - only allow drawing here
-	if (is_visible_in_tree()) { //todo optimize this!!
-		if (first_draw) {
-			notification(NOTIFICATION_VISIBILITY_CHANGED);
-			first_draw = false;
-		}
-		drawing = true;
-		current_item_drawn = this;
-		notification(NOTIFICATION_DRAW);
-		emit_signal(SceneStringNames::get_singleton()->draw);
-		if (get_script_instance()) {
-			get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw, NULL, 0);
-		}
-		current_item_drawn = NULL;
-		drawing = false;
-	}
-	//todo updating = false
-	pending_update = false; // don't change to false until finished drawing (avoid recursive update)
-}
-
-Transform2D CanvasItem::get_global_transform_with_canvas() const {
-
-	if (canvas_layer)
-		return canvas_layer->get_transform() * get_global_transform();
-	else if (is_inside_tree())
-		return get_viewport()->get_canvas_transform() * get_global_transform();
-	else
-		return get_global_transform();
-}
-
-Transform2D CanvasItem::get_screen_transform() const {
-	ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
-	Transform2D xform = get_global_transform_with_canvas();
-
-	Window *w = Object::cast_to<Window>(get_viewport());
-	if (w && !w->is_embedding_subwindows()) {
-		Transform2D s;
-		s.set_origin(w->get_position());
-
-		xform = s * xform;
-	}
-
-	return xform;
-}
-
-Transform2D CanvasItem::get_global_transform() const {
-#ifdef DEBUG_ENABLED
-	ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
-#endif
-	if (global_invalid) {
-
-		const CanvasItem *pi = get_parent_item();
-		if (pi)
-			global_transform = pi->get_global_transform() * get_transform();
-		else
-			global_transform = get_transform();
-
-		global_invalid = false;
-	}
-
-	return global_transform;
-}
-
-void CanvasItem::_toplevel_raise_self() {
-
-	if (!is_inside_tree())
-		return;
-
-	if (canvas_layer)
-		VisualServer::get_singleton()->canvas_item_set_draw_index(canvas_item, canvas_layer->get_sort_index());
-	else
-		VisualServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_viewport()->gui_get_canvas_sort_index());
-}
-
-void CanvasItem::_enter_canvas() {
-
-	if ((!Object::cast_to<CanvasItem>(get_parent())) || toplevel) {
-
-		Node *n = this;
-
-		canvas_layer = NULL;
-
-		while (n) {
-
-			canvas_layer = Object::cast_to<CanvasLayer>(n);
-			if (canvas_layer) {
-				break;
-			}
-			if (Object::cast_to<Viewport>(n)) {
-				break;
-			}
-			n = n->get_parent();
-		}
-
-		RID canvas;
-		if (canvas_layer)
-			canvas = canvas_layer->get_canvas();
-		else
-			canvas = get_viewport()->find_world_2d()->get_canvas();
-
-		VisualServer::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
-
-		group = "root_canvas" + itos(canvas.get_id());
-
-		add_to_group(group);
-		if (canvas_layer)
-			canvas_layer->reset_sort_index();
-		else
-			get_viewport()->gui_reset_canvas_sort_index();
-
-		get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
-
-	} else {
-
-		CanvasItem *parent = get_parent_item();
-		canvas_layer = parent->canvas_layer;
-		VisualServer::get_singleton()->canvas_item_set_parent(canvas_item, parent->get_canvas_item());
-		VisualServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
-	}
-
-	pending_update = false;
-	update();
-
-	notification(NOTIFICATION_ENTER_CANVAS);
-}
-
-void CanvasItem::_exit_canvas() {
-
-	notification(NOTIFICATION_EXIT_CANVAS, true); //reverse the notification
-	VisualServer::get_singleton()->canvas_item_set_parent(canvas_item, RID());
-	canvas_layer = NULL;
-	group = "";
-}
-
-void CanvasItem::_notification(int p_what) {
-
-	switch (p_what) {
-		case NOTIFICATION_ENTER_TREE: {
-
-			_update_texture_filter_changed(false);
-			_update_texture_repeat_changed(false);
-
-			first_draw = true;
-			Node *parent = get_parent();
-			if (parent) {
-				CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
-				if (ci)
-					C = ci->children_items.push_back(this);
-				if (!ci) {
-					//look for a window
-					Viewport *viewport = nullptr;
-
-					while (parent) {
-						viewport = Object::cast_to<Viewport>(parent);
-						if (viewport) {
-							break;
-						}
-						parent = parent->get_parent();
-					}
-
-					ERR_FAIL_COND(!viewport);
-
-					window = Object::cast_to<Window>(viewport);
-					if (window) {
-						window->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
-					}
-				}
-			}
-			_enter_canvas();
-			if (!block_transform_notify && !xform_change.in_list()) {
-				get_tree()->xform_change_list.add(&xform_change);
-			}
-		} break;
-		case NOTIFICATION_MOVED_IN_PARENT: {
-
-			if (!is_inside_tree())
-				break;
-
-			if (group != "") {
-				get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE, group, "_toplevel_raise_self");
-			} else {
-				CanvasItem *p = get_parent_item();
-				ERR_FAIL_COND(!p);
-				VisualServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
-			}
-
-		} break;
-		case NOTIFICATION_EXIT_TREE: {
-			if (xform_change.in_list())
-				get_tree()->xform_change_list.remove(&xform_change);
-			_exit_canvas();
-			if (C) {
-				Object::cast_to<CanvasItem>(get_parent())->children_items.erase(C);
-				C = NULL;
-			}
-			if (window) {
-				window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
-			}
-			global_invalid = true;
-		} break;
-		case NOTIFICATION_DRAW:
-		case NOTIFICATION_TRANSFORM_CHANGED: {
-
-		} break;
-		case NOTIFICATION_VISIBILITY_CHANGED: {
-
-			emit_signal(SceneStringNames::get_singleton()->visibility_changed);
-		} break;
-	}
-}
-
-void CanvasItem::set_visible(bool p_visible) {
-
-	if (p_visible)
-		show();
-	else
-		hide();
-}
-
-void CanvasItem::_window_visibility_changed() {
-
-	if (visible) {
-		_propagate_visibility_changed(window->is_visible());
-	}
-}
-
-bool CanvasItem::is_visible() const {
-
-	return visible;
-}
-
-void CanvasItem::update() {
-
-	if (!is_inside_tree())
-		return;
-	if (pending_update)
-		return;
-
-	pending_update = true;
-
-	MessageQueue::get_singleton()->push_call(this, "_update_callback");
-}
-
-void CanvasItem::set_modulate(const Color &p_modulate) {
-
-	if (modulate == p_modulate)
-		return;
-
-	modulate = p_modulate;
-	VisualServer::get_singleton()->canvas_item_set_modulate(canvas_item, modulate);
-}
-Color CanvasItem::get_modulate() const {
-
-	return modulate;
-}
-
-void CanvasItem::set_as_toplevel(bool p_toplevel) {
-
-	if (toplevel == p_toplevel)
-		return;
-
-	if (!is_inside_tree()) {
-		toplevel = p_toplevel;
-		return;
-	}
-
-	_exit_canvas();
-	toplevel = p_toplevel;
-	_enter_canvas();
-}
-
-bool CanvasItem::is_set_as_toplevel() const {
-
-	return toplevel;
-}
-
-CanvasItem *CanvasItem::get_parent_item() const {
-
-	if (toplevel)
-		return NULL;
-
-	return Object::cast_to<CanvasItem>(get_parent());
-}
-
-void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
-
-	if (self_modulate == p_self_modulate)
-		return;
-
-	self_modulate = p_self_modulate;
-	VisualServer::get_singleton()->canvas_item_set_self_modulate(canvas_item, self_modulate);
-}
-Color CanvasItem::get_self_modulate() const {
-
-	return self_modulate;
-}
-
-void CanvasItem::set_light_mask(int p_light_mask) {
-
-	if (light_mask == p_light_mask)
-		return;
-
-	light_mask = p_light_mask;
-	VS::get_singleton()->canvas_item_set_light_mask(canvas_item, p_light_mask);
-}
-
-int CanvasItem::get_light_mask() const {
-
-	return light_mask;
-}
-
-void CanvasItem::item_rect_changed(bool p_size_changed) {
-
-	if (p_size_changed)
-		update();
-	emit_signal(SceneStringNames::get_singleton()->item_rect_changed);
-}
-
-void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width);
-}
-
-void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	Vector<Color> colors;
-	colors.push_back(p_color);
-	VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width);
-}
-
-void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width);
-}
-
-void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width) {
-
-	Vector<Point2> points;
-	points.resize(p_point_count);
-	const float delta_angle = p_end_angle - p_start_angle;
-	for (int i = 0; i < p_point_count; i++) {
-		float theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
-		points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
-	}
-
-	draw_polyline(points, p_color, p_width);
-}
-
-void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	Vector<Color> colors;
-	colors.push_back(p_color);
-	VisualServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width);
-}
-
-void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	VisualServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width);
-}
-
-void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, float p_width) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	if (p_filled) {
-		if (p_width != 1.0) {
-			WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\".");
-		}
-
-		VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color);
-	} else {
-		// Thick lines are offset depending on their width to avoid partial overlapping.
-		// Thin lines don't require an offset, so don't apply one in this case
-		float offset;
-		if (p_width >= 2) {
-			offset = p_width / 2.0;
-		} else {
-			offset = 0.0;
-		}
-
-		VisualServer::get_singleton()->canvas_item_add_line(
-				canvas_item,
-				p_rect.position + Size2(-offset, 0),
-				p_rect.position + Size2(p_rect.size.width + offset, 0),
-				p_color,
-				p_width);
-		VisualServer::get_singleton()->canvas_item_add_line(
-				canvas_item,
-				p_rect.position + Size2(p_rect.size.width, offset),
-				p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset),
-				p_color,
-				p_width);
-		VisualServer::get_singleton()->canvas_item_add_line(
-				canvas_item,
-				p_rect.position + Size2(p_rect.size.width + offset, p_rect.size.height),
-				p_rect.position + Size2(-offset, p_rect.size.height),
-				p_color,
-				p_width);
-		VisualServer::get_singleton()->canvas_item_add_line(
-				canvas_item,
-				p_rect.position + Size2(0, p_rect.size.height - offset),
-				p_rect.position + Size2(0, offset),
-				p_color,
-				p_width);
-	}
-}
-
-void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	VisualServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
-}
-
-void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	ERR_FAIL_COND(p_texture.is_null());
-
-	p_texture->draw(canvas_item, p_pos, p_modulate, false, p_normal_map, p_specular_map, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-
-void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	ERR_FAIL_COND(p_texture.is_null());
-	p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, bool p_clip_uv, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-	ERR_FAIL_COND(p_texture.is_null());
-	p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_normal_map, p_specular_map, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat), p_clip_uv);
-}
-
-void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	ERR_FAIL_COND(p_style_box.is_null());
-
-	p_style_box->draw(canvas_item, p_rect);
-}
-void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, float p_width, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
-	RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
-	RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
-	VisualServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width, rid_normal, rid_specular, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-void CanvasItem::draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	Transform2D xform(p_rot, p_offset);
-	xform.scale_basis(p_scale);
-	VisualServer::get_singleton()->canvas_item_add_set_transform(canvas_item, xform);
-}
-
-void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	VisualServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
-}
-
-void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
-	RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
-	RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
-	VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-
-void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	Vector<Color> colors;
-	colors.push_back(p_color);
-	RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
-	RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
-	RID rid_specular = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
-	VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, rid_specular, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-
-void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, const Transform2D &p_transform, const Color &p_modulate, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
-	ERR_FAIL_COND(p_mesh.is_null());
-	RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
-	RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
-	RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
-	VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, TextureFilter p_texture_filter, TextureRepeat p_texture_repeat) {
-
-	ERR_FAIL_COND(p_multimesh.is_null());
-	RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
-	RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
-	RID specular_map_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID();
-
-	VisualServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid, normal_map_rid, specular_map_rid, p_specular_color_shininess, VS::CanvasItemTextureFilter(p_texture_filter), VS::CanvasItemTextureRepeat(p_texture_repeat));
-}
-
-void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) {
-
-	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	ERR_FAIL_COND(p_font.is_null());
-	p_font->draw(canvas_item, p_pos, p_text, p_modulate, p_clip_w);
-}
-
-float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, const Color &p_modulate) {
-
-	ERR_FAIL_COND_V_MSG(!drawing, 0, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
-
-	ERR_FAIL_COND_V(p_char.length() != 1, 0);
-	ERR_FAIL_COND_V(p_font.is_null(), 0);
-
-	if (p_font->has_outline()) {
-		p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], Color(1, 1, 1), true);
-	}
-	return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], p_modulate);
-}
-
-void CanvasItem::_notify_transform(CanvasItem *p_node) {
-
-	/* This check exists to avoid re-propagating the transform
-	 * notification down the tree on dirty nodes. It provides
-	 * optimization by avoiding redundancy (nodes are dirty, will get the
-	 * notification anyway).
-	 */
-
-	if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) {
-		return; //nothing to do
-	}
-
-	p_node->global_invalid = true;
-
-	if (p_node->notify_transform && !p_node->xform_change.in_list()) {
-		if (!p_node->block_transform_notify) {
-			if (p_node->is_inside_tree())
-				get_tree()->xform_change_list.add(&p_node->xform_change);
-		}
-	}
-
-	for (List<CanvasItem *>::Element *E = p_node->children_items.front(); E; E = E->next()) {
-
-		CanvasItem *ci = E->get();
-		if (ci->toplevel)
-			continue;
-		_notify_transform(ci);
-	}
-}
-
-Rect2 CanvasItem::get_viewport_rect() const {
-
-	ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
-	return get_viewport()->get_visible_rect();
-}
-
-RID CanvasItem::get_canvas() const {
-
-	ERR_FAIL_COND_V(!is_inside_tree(), RID());
-
-	if (canvas_layer)
-		return canvas_layer->get_canvas();
-	else
-		return get_viewport()->find_world_2d()->get_canvas();
-}
-
-ObjectID CanvasItem::get_canvas_layer_instance_id() const {
-
-	if (canvas_layer) {
-		return canvas_layer->get_instance_id();
-	} else {
-		return ObjectID();
-	}
-}
-
-CanvasItem *CanvasItem::get_toplevel() const {
-
-	CanvasItem *ci = const_cast<CanvasItem *>(this);
-	while (!ci->toplevel && Object::cast_to<CanvasItem>(ci->get_parent())) {
-		ci = Object::cast_to<CanvasItem>(ci->get_parent());
-	}
-
-	return ci;
-}
-
-Ref<World2D> CanvasItem::get_world_2d() const {
-
-	ERR_FAIL_COND_V(!is_inside_tree(), Ref<World2D>());
-
-	CanvasItem *tl = get_toplevel();
-
-	if (tl->get_viewport()) {
-		return tl->get_viewport()->find_world_2d();
-	} else {
-		return Ref<World2D>();
-	}
-}
-
-RID CanvasItem::get_viewport_rid() const {
-
-	ERR_FAIL_COND_V(!is_inside_tree(), RID());
-	return get_viewport()->get_viewport_rid();
-}
-
-void CanvasItem::set_block_transform_notify(bool p_enable) {
-	block_transform_notify = p_enable;
-}
-
-bool CanvasItem::is_block_transform_notify_enabled() const {
-
-	return block_transform_notify;
-}
-
-void CanvasItem::set_draw_behind_parent(bool p_enable) {
-
-	if (behind == p_enable)
-		return;
-	behind = p_enable;
-	VisualServer::get_singleton()->canvas_item_set_draw_behind_parent(canvas_item, behind);
-}
-
-bool CanvasItem::is_draw_behind_parent_enabled() const {
-
-	return behind;
-}
-
-void CanvasItem::set_material(const Ref<Material> &p_material) {
-
-	material = p_material;
-	RID rid;
-	if (material.is_valid())
-		rid = material->get_rid();
-	VS::get_singleton()->canvas_item_set_material(canvas_item, rid);
-	_change_notify(); //properties for material exposed
-}
-
-void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
-
-	use_parent_material = p_use_parent_material;
-	VS::get_singleton()->canvas_item_set_use_parent_material(canvas_item, p_use_parent_material);
-}
-
-bool CanvasItem::get_use_parent_material() const {
-
-	return use_parent_material;
-}
-
-Ref<Material> CanvasItem::get_material() const {
-
-	return material;
-}
-
-Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) const {
-
-	ERR_FAIL_COND_V(!is_inside_tree(), screen_point);
-
-	Transform2D local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();
-
-	return local_matrix.xform(screen_point);
-}
-
-Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const {
-
-	ERR_FAIL_COND_V(p_event.is_null(), p_event);
-	ERR_FAIL_COND_V(!is_inside_tree(), p_event);
-
-	return p_event->xformed_by((get_canvas_transform() * get_global_transform()).affine_inverse());
-}
-
-Vector2 CanvasItem::get_global_mouse_position() const {
-
-	ERR_FAIL_COND_V(!get_viewport(), Vector2());
-	return get_canvas_transform().affine_inverse().xform(get_viewport()->get_mouse_position());
-}
-
-Vector2 CanvasItem::get_local_mouse_position() const {
-
-	ERR_FAIL_COND_V(!get_viewport(), Vector2());
-
-	return get_global_transform().affine_inverse().xform(get_global_mouse_position());
-}
-
-void CanvasItem::force_update_transform() {
-	ERR_FAIL_COND(!is_inside_tree());
-	if (!xform_change.in_list()) {
-		return;
-	}
-
-	get_tree()->xform_change_list.remove(&xform_change);
-
-	notification(NOTIFICATION_TRANSFORM_CHANGED);
-}
-
-void CanvasItem::_bind_methods() {
-
-	ClassDB::bind_method(D_METHOD("_toplevel_raise_self"), &CanvasItem::_toplevel_raise_self);
-	ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback);
-
-#ifdef TOOLS_ENABLED
-	ClassDB::bind_method(D_METHOD("_edit_set_state", "state"), &CanvasItem::_edit_set_state);
-	ClassDB::bind_method(D_METHOD("_edit_get_state"), &CanvasItem::_edit_get_state);
-	ClassDB::bind_method(D_METHOD("_edit_set_position", "position"), &CanvasItem::_edit_set_position);
-	ClassDB::bind_method(D_METHOD("_edit_get_position"), &CanvasItem::_edit_get_position);
-	ClassDB::bind_method(D_METHOD("_edit_set_scale", "scale"), &CanvasItem::_edit_set_scale);
-	ClassDB::bind_method(D_METHOD("_edit_get_scale"), &CanvasItem::_edit_get_scale);
-	ClassDB::bind_method(D_METHOD("_edit_set_rect", "rect"), &CanvasItem::_edit_set_rect);
-	ClassDB::bind_method(D_METHOD("_edit_get_rect"), &CanvasItem::_edit_get_rect);
-	ClassDB::bind_method(D_METHOD("_edit_use_rect"), &CanvasItem::_edit_use_rect);
-	ClassDB::bind_method(D_METHOD("_edit_set_rotation", "degrees"), &CanvasItem::_edit_set_rotation);
-	ClassDB::bind_method(D_METHOD("_edit_get_rotation"), &CanvasItem::_edit_get_rotation);
-	ClassDB::bind_method(D_METHOD("_edit_use_rotation"), &CanvasItem::_edit_use_rotation);
-	ClassDB::bind_method(D_METHOD("_edit_set_pivot", "pivot"), &CanvasItem::_edit_set_pivot);
-	ClassDB::bind_method(D_METHOD("_edit_get_pivot"), &CanvasItem::_edit_get_pivot);
-	ClassDB::bind_method(D_METHOD("_edit_use_pivot"), &CanvasItem::_edit_use_pivot);
-	ClassDB::bind_method(D_METHOD("_edit_get_transform"), &CanvasItem::_edit_get_transform);
-#endif
-
-	ClassDB::bind_method(D_METHOD("get_canvas_item"), &CanvasItem::get_canvas_item);
-
-	ClassDB::bind_method(D_METHOD("set_visible", "visible"), &CanvasItem::set_visible);
-	ClassDB::bind_method(D_METHOD("is_visible"), &CanvasItem::is_visible);
-	ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &CanvasItem::is_visible_in_tree);
-	ClassDB::bind_method(D_METHOD("show"), &CanvasItem::show);
-	ClassDB::bind_method(D_METHOD("hide"), &CanvasItem::hide);
-
-	ClassDB::bind_method(D_METHOD("update"), &CanvasItem::update);
-
-	ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &CanvasItem::set_as_toplevel);
-	ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &CanvasItem::is_set_as_toplevel);
-
-	ClassDB::bind_method(D_METHOD("set_light_mask", "light_mask"), &CanvasItem::set_light_mask);
-	ClassDB::bind_method(D_METHOD("get_light_mask"), &CanvasItem::get_light_mask);
-
-	ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &CanvasItem::set_modulate);
-	ClassDB::bind_method(D_METHOD("get_modulate"), &CanvasItem::get_modulate);
-	ClassDB::bind_method(D_METHOD("set_self_modulate", "self_modulate"), &CanvasItem::set_self_modulate);
-	ClassDB::bind_method(D_METHOD("get_self_modulate"), &CanvasItem::get_self_modulate);
-
-	ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent);
-	ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled);
-
-	ClassDB::bind_method(D_METHOD("_set_on_top", "on_top"), &CanvasItem::_set_on_top);
-	ClassDB::bind_method(D_METHOD("_is_on_top"), &CanvasItem::_is_on_top);
-	//ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
-
-	ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width"), &CanvasItem::draw_line, DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width"), &CanvasItem::draw_polyline, DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width"), &CanvasItem::draw_arc, DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
-	ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-	ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-	ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "normal_map", "specular_map", "specular_shininess", "clip_uv", "texture_filter", "texture_repeat"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(true), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-	ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
-	ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-	ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-	ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-	ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(-1));
-	ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1, 1)));
-	ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "specular_map", "specular_shininess", "transform", "modulate", "texture_filter", "texture_repeat"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-	ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map", "specular_map", "specular_shininess", "texture_filter", "texture_repeat"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(Color(1, 1, 1, 1)), DEFVAL(TEXTURE_FILTER_PARENT_NODE), DEFVAL(TEXTURE_REPEAT_PARENT_NODE));
-
-	ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
-	ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix);
-	ClassDB::bind_method(D_METHOD("get_transform"), &CanvasItem::get_transform);
-	ClassDB::bind_method(D_METHOD("get_global_transform"), &CanvasItem::get_global_transform);
-	ClassDB::bind_method(D_METHOD("get_global_transform_with_canvas"), &CanvasItem::get_global_transform_with_canvas);
-	ClassDB::bind_method(D_METHOD("get_viewport_transform"), &CanvasItem::get_viewport_transform);
-	ClassDB::bind_method(D_METHOD("get_viewport_rect"), &CanvasItem::get_viewport_rect);
-	ClassDB::bind_method(D_METHOD("get_canvas_transform"), &CanvasItem::get_canvas_transform);
-	ClassDB::bind_method(D_METHOD("get_local_mouse_position"), &CanvasItem::get_local_mouse_position);
-	ClassDB::bind_method(D_METHOD("get_global_mouse_position"), &CanvasItem::get_global_mouse_position);
-	ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasItem::get_canvas);
-	ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d);
-	//ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport);
-
-	ClassDB::bind_method(D_METHOD("set_material", "material"), &CanvasItem::set_material);
-	ClassDB::bind_method(D_METHOD("get_material"), &CanvasItem::get_material);
-
-	ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material);
-	ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material);
-
-	ClassDB::bind_method(D_METHOD("set_notify_local_transform", "enable"), &CanvasItem::set_notify_local_transform);
-	ClassDB::bind_method(D_METHOD("is_local_transform_notification_enabled"), &CanvasItem::is_local_transform_notification_enabled);
-
-	ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &CanvasItem::set_notify_transform);
-	ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &CanvasItem::is_transform_notification_enabled);
-
-	ClassDB::bind_method(D_METHOD("force_update_transform"), &CanvasItem::force_update_transform);
-
-	ClassDB::bind_method(D_METHOD("make_canvas_position_local", "screen_point"), &CanvasItem::make_canvas_position_local);
-	ClassDB::bind_method(D_METHOD("make_input_local", "event"), &CanvasItem::make_input_local);
-
-	ClassDB::bind_method(D_METHOD("set_texture_filter", "mode"), &CanvasItem::set_texture_filter);
-	ClassDB::bind_method(D_METHOD("get_texture_filter"), &CanvasItem::get_texture_filter);
-
-	ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
-	ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
-
-	BIND_VMETHOD(MethodInfo("_draw"));
-
-	ADD_GROUP("Visibility", "");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
-	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
-	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
-
-	ADD_GROUP("Texture", "texture_");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "ParentNode,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "ParentNode,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
-
-	ADD_GROUP("Material", "");
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
-	//exporting these things doesn't really make much sense i think
-	// ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toplevel", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_as_toplevel", "is_set_as_toplevel");
-	// ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled");
-
-	ADD_SIGNAL(MethodInfo("draw"));
-	ADD_SIGNAL(MethodInfo("visibility_changed"));
-	ADD_SIGNAL(MethodInfo("hide"));
-	ADD_SIGNAL(MethodInfo("item_rect_changed"));
-
-	BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
-	BIND_CONSTANT(NOTIFICATION_DRAW);
-	BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
-	BIND_CONSTANT(NOTIFICATION_ENTER_CANVAS);
-	BIND_CONSTANT(NOTIFICATION_EXIT_CANVAS);
-
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_PARENT_NODE);
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST);
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR);
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC);
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC);
-	BIND_ENUM_CONSTANT(TEXTURE_FILTER_MAX);
-
-	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_PARENT_NODE);
-	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_DISABLED);
-	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
-	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
-	BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
-}
-
-Transform2D CanvasItem::get_canvas_transform() const {
-
-	ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
-
-	if (canvas_layer)
-		return canvas_layer->get_transform();
-	else if (Object::cast_to<CanvasItem>(get_parent()))
-		return Object::cast_to<CanvasItem>(get_parent())->get_canvas_transform();
-	else
-		return get_viewport()->get_canvas_transform();
-}
-
-Transform2D CanvasItem::get_viewport_transform() const {
-
-	ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
-
-	if (canvas_layer) {
-
-		if (get_viewport()) {
-			return get_viewport()->get_final_transform() * canvas_layer->get_transform();
-		} else {
-			return canvas_layer->get_transform();
-		}
-
-	} else {
-		return get_viewport()->get_final_transform() * get_viewport()->get_canvas_transform();
-	}
-}
-
-void CanvasItem::set_notify_local_transform(bool p_enable) {
-	notify_local_transform = p_enable;
-}
-
-bool CanvasItem::is_local_transform_notification_enabled() const {
-	return notify_local_transform;
-}
-
-void CanvasItem::set_notify_transform(bool p_enable) {
-	if (notify_transform == p_enable)
-		return;
-
-	notify_transform = p_enable;
-
-	if (notify_transform && is_inside_tree()) {
-		//this ensures that invalid globals get resolved, so notifications can be received
-		get_global_transform();
-	}
-}
-
-bool CanvasItem::is_transform_notification_enabled() const {
-	return notify_transform;
-}
-
-int CanvasItem::get_canvas_layer() const {
-
-	if (canvas_layer)
-		return canvas_layer->get_layer();
-	else
-		return 0;
-}
-
-void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
-
-	if (!is_inside_tree()) {
-		return;
-	}
-
-	if (texture_filter == TEXTURE_FILTER_PARENT_NODE) {
-		CanvasItem *parent_item = get_parent_item();
-		if (parent_item) {
-			texture_filter_cache = parent_item->texture_filter_cache;
-		} else {
-			//from viewport
-			switch (get_viewport()->get_default_canvas_item_texture_filter()) {
-				case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST: texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST; break;
-				case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR: texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; break;
-				case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; break;
-				case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS; break;
-				default: {
-				}
-			}
-		}
-	} else {
-		texture_filter_cache = VS::CanvasItemTextureFilter(texture_filter);
-	}
-	VS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
-	update();
-
-	if (p_propagate) {
-		for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
-			if (!E->get()->toplevel && E->get()->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
-				E->get()->_update_texture_filter_changed(true);
-			}
-		}
-	}
-}
-
-void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
-	ERR_FAIL_INDEX(p_texture_filter, TEXTURE_FILTER_MAX);
-	if (texture_filter == p_texture_filter) {
-		return;
-	}
-	texture_filter = p_texture_filter;
-	_update_texture_filter_changed(true);
-}
-
-CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
-	return texture_filter;
-}
-
-void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
-
-	if (!is_inside_tree()) {
-		return;
-	}
-
-	if (texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
-		CanvasItem *parent_item = get_parent_item();
-		if (parent_item) {
-			texture_repeat_cache = parent_item->texture_repeat_cache;
-		} else {
-			//from viewport
-			switch (get_viewport()->get_default_canvas_item_texture_repeat()) {
-				case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: texture_repeat_cache = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; break;
-				case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: texture_repeat_cache = VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; break;
-				case Viewport::DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: texture_repeat_cache = VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR; break;
-				default: {
-				}
-			}
-		}
-	} else {
-		texture_repeat_cache = VS::CanvasItemTextureRepeat(texture_repeat);
-	}
-	VS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
-	update();
-	if (p_propagate) {
-		for (List<CanvasItem *>::Element *E = children_items.front(); E; E = E->next()) {
-			if (!E->get()->toplevel && E->get()->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
-				E->get()->_update_texture_repeat_changed(true);
-			}
-		}
-	}
-}
-
-void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
-	ERR_FAIL_INDEX(p_texture_repeat, TEXTURE_REPEAT_MAX);
-	if (texture_repeat == p_texture_repeat) {
-		return;
-	}
-	texture_repeat = p_texture_repeat;
-	_update_texture_repeat_changed(true);
-}
-
-CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
-	return texture_repeat;
-}
-
-CanvasItem::CanvasItem() :
-		xform_change(this) {
-
-	window = nullptr;
-	canvas_item = VisualServer::get_singleton()->canvas_item_create();
-	visible = true;
-	pending_update = false;
-	modulate = Color(1, 1, 1, 1);
-	self_modulate = Color(1, 1, 1, 1);
-	toplevel = false;
-	first_draw = false;
-	drawing = false;
-	behind = false;
-	block_transform_notify = false;
-	//viewport=NULL;
-	canvas_layer = NULL;
-	use_parent_material = false;
-	global_invalid = true;
-	notify_local_transform = false;
-	notify_transform = false;
-	light_mask = 1;
-	texture_repeat = TEXTURE_REPEAT_PARENT_NODE;
-	texture_filter = TEXTURE_FILTER_PARENT_NODE;
-	texture_filter_cache = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
-	texture_repeat_cache = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
-
-	C = NULL;
-}
-
-CanvasItem::~CanvasItem() {
-
-	VisualServer::get_singleton()->free(canvas_item);
-}
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
deleted file mode 100644
index 3f176e5f60..0000000000
--- a/scene/2d/canvas_item.h
+++ /dev/null
@@ -1,426 +0,0 @@
-/*************************************************************************/
-/*  canvas_item.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 CANVAS_ITEM_H
-#define CANVAS_ITEM_H
-
-#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
-#include "scene/resources/material.h"
-#include "scene/resources/multimesh.h"
-#include "scene/resources/shader.h"
-#include "scene/resources/texture.h"
-
-class CanvasLayer;
-class Viewport;
-class Font;
-
-class StyleBox;
-
-class CanvasItemMaterial : public Material {
-
-	GDCLASS(CanvasItemMaterial, Material);
-
-public:
-	enum BlendMode {
-		BLEND_MODE_MIX,
-		BLEND_MODE_ADD,
-		BLEND_MODE_SUB,
-		BLEND_MODE_MUL,
-		BLEND_MODE_PREMULT_ALPHA,
-		BLEND_MODE_DISABLED
-	};
-
-	enum LightMode {
-		LIGHT_MODE_NORMAL,
-		LIGHT_MODE_UNSHADED,
-		LIGHT_MODE_LIGHT_ONLY
-	};
-
-private:
-	union MaterialKey {
-
-		struct {
-			uint32_t blend_mode : 4;
-			uint32_t light_mode : 4;
-			uint32_t particles_animation : 1;
-			uint32_t invalid_key : 1;
-		};
-
-		uint32_t key;
-
-		bool operator<(const MaterialKey &p_key) const {
-			return key < p_key.key;
-		}
-	};
-
-	struct ShaderNames {
-		StringName particles_anim_h_frames;
-		StringName particles_anim_v_frames;
-		StringName particles_anim_loop;
-	};
-
-	static ShaderNames *shader_names;
-
-	struct ShaderData {
-		RID shader;
-		int users;
-	};
-
-	static Map<MaterialKey, ShaderData> shader_map;
-
-	MaterialKey current_key;
-
-	_FORCE_INLINE_ MaterialKey _compute_key() const {
-
-		MaterialKey mk;
-		mk.key = 0;
-		mk.blend_mode = blend_mode;
-		mk.light_mode = light_mode;
-		mk.particles_animation = particles_animation;
-		return mk;
-	}
-
-	static Mutex material_mutex;
-	static SelfList<CanvasItemMaterial>::List *dirty_materials;
-	SelfList<CanvasItemMaterial> element;
-
-	void _update_shader();
-	_FORCE_INLINE_ void _queue_shader_change();
-	_FORCE_INLINE_ bool _is_shader_dirty() const;
-
-	BlendMode blend_mode;
-	LightMode light_mode;
-	bool particles_animation;
-
-	int particles_anim_h_frames;
-	int particles_anim_v_frames;
-	bool particles_anim_loop;
-
-protected:
-	static void _bind_methods();
-	void _validate_property(PropertyInfo &property) const;
-
-public:
-	void set_blend_mode(BlendMode p_blend_mode);
-	BlendMode get_blend_mode() const;
-
-	void set_light_mode(LightMode p_light_mode);
-	LightMode get_light_mode() const;
-
-	void set_particles_animation(bool p_particles_anim);
-	bool get_particles_animation() const;
-
-	void set_particles_anim_h_frames(int p_frames);
-	int get_particles_anim_h_frames() const;
-	void set_particles_anim_v_frames(int p_frames);
-	int get_particles_anim_v_frames() const;
-
-	void set_particles_anim_loop(bool p_loop);
-	bool get_particles_anim_loop() const;
-
-	static void init_shaders();
-	static void finish_shaders();
-	static void flush_changes();
-
-	RID get_shader_rid() const;
-
-	virtual Shader::Mode get_shader_mode() const;
-
-	CanvasItemMaterial();
-	virtual ~CanvasItemMaterial();
-};
-
-VARIANT_ENUM_CAST(CanvasItemMaterial::BlendMode)
-VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode)
-
-class CanvasItem : public Node {
-
-	GDCLASS(CanvasItem, Node);
-
-public:
-	enum TextureFilter {
-		TEXTURE_FILTER_PARENT_NODE,
-		TEXTURE_FILTER_NEAREST,
-		TEXTURE_FILTER_LINEAR,
-		TEXTURE_FILTER_NEAREST_WITH_MIPMAPS,
-		TEXTURE_FILTER_LINEAR_WITH_MIPMAPS,
-		TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC,
-		TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC,
-		TEXTURE_FILTER_MAX
-	};
-
-	enum TextureRepeat {
-		TEXTURE_REPEAT_PARENT_NODE,
-		TEXTURE_REPEAT_DISABLED,
-		TEXTURE_REPEAT_ENABLED,
-		TEXTURE_REPEAT_MIRROR,
-		TEXTURE_REPEAT_MAX,
-	};
-
-private:
-	mutable SelfList<Node> xform_change;
-
-	RID canvas_item;
-	String group;
-
-	CanvasLayer *canvas_layer;
-
-	Color modulate;
-	Color self_modulate;
-
-	List<CanvasItem *> children_items;
-	List<CanvasItem *>::Element *C;
-
-	int light_mask;
-
-	Window *window;
-	bool first_draw;
-	bool visible;
-	bool pending_update;
-	bool toplevel;
-	bool drawing;
-	bool block_transform_notify;
-	bool behind;
-	bool use_parent_material;
-	bool notify_local_transform;
-	bool notify_transform;
-
-	VS::CanvasItemTextureFilter texture_filter_cache;
-	VS::CanvasItemTextureRepeat texture_repeat_cache;
-
-	TextureFilter texture_filter;
-	TextureRepeat texture_repeat;
-
-	Ref<Material> material;
-
-	mutable Transform2D global_transform;
-	mutable bool global_invalid;
-
-	void _toplevel_raise_self();
-
-	void _propagate_visibility_changed(bool p_visible);
-
-	void _update_callback();
-
-	void _enter_canvas();
-	void _exit_canvas();
-
-	void _window_visibility_changed();
-
-	void _notify_transform(CanvasItem *p_node);
-
-	void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); }
-	bool _is_on_top() const { return !is_draw_behind_parent_enabled(); }
-
-	static CanvasItem *current_item_drawn;
-	friend class Viewport;
-	void _update_texture_repeat_changed(bool p_propagate);
-	void _update_texture_filter_changed(bool p_propagate);
-
-protected:
-	_FORCE_INLINE_ void _notify_transform() {
-		if (!is_inside_tree()) return;
-		_notify_transform(this);
-		if (!block_transform_notify && notify_local_transform) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
-	}
-
-	void item_rect_changed(bool p_size_changed = true);
-
-	void _notification(int p_what);
-	static void _bind_methods();
-
-public:
-	enum {
-		NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique
-		NOTIFICATION_DRAW = 30,
-		NOTIFICATION_VISIBILITY_CHANGED = 31,
-		NOTIFICATION_ENTER_CANVAS = 32,
-		NOTIFICATION_EXIT_CANVAS = 33,
-		NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 35,
-		NOTIFICATION_WORLD_2D_CHANGED = 36,
-
-	};
-
-	/* EDITOR */
-#ifdef TOOLS_ENABLED
-	// Select the node
-	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-
-	// Save and restore a CanvasItem state
-	virtual void _edit_set_state(const Dictionary &p_state){};
-	virtual Dictionary _edit_get_state() const { return Dictionary(); };
-
-	// Used to move the node
-	virtual void _edit_set_position(const Point2 &p_position) = 0;
-	virtual Point2 _edit_get_position() const = 0;
-
-	// Used to scale the node
-	virtual void _edit_set_scale(const Size2 &p_scale) = 0;
-	virtual Size2 _edit_get_scale() const = 0;
-
-	// Used to rotate the node
-	virtual bool _edit_use_rotation() const { return false; };
-	virtual void _edit_set_rotation(float p_rotation){};
-	virtual float _edit_get_rotation() const { return 0.0; };
-
-	// Used to resize/move the node
-	virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
-	virtual void _edit_set_rect(const Rect2 &p_rect){};
-	virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); };
-	virtual Size2 _edit_get_minimum_size() const { return Size2(-1, -1); }; // LOOKS WEIRD
-
-	// Used to set a pivot
-	virtual bool _edit_use_pivot() const { return false; };
-	virtual void _edit_set_pivot(const Point2 &p_pivot){};
-	virtual Point2 _edit_get_pivot() const { return Point2(); };
-
-	virtual Transform2D _edit_get_transform() const;
-#endif
-
-	/* VISIBILITY */
-
-	void set_visible(bool p_visible);
-	bool is_visible() const;
-	bool is_visible_in_tree() const;
-	void show();
-	void hide();
-
-	void update();
-
-	virtual void set_light_mask(int p_light_mask);
-	int get_light_mask() const;
-
-	void set_modulate(const Color &p_modulate);
-	Color get_modulate() const;
-
-	void set_self_modulate(const Color &p_self_modulate);
-	Color get_self_modulate() const;
-
-	/* DRAWING API */
-
-	void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
-	void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0);
-	void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
-	void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0);
-	void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0);
-	void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
-	void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0);
-	void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color);
-	void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-	void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-	void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), bool p_clip_uv = false, TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-	void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
-	void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), float p_width = 1, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-	void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-	void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>(), const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-
-	void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-	void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_normal_map = Ref<Texture2D>(), const Ref<Texture2D> &p_specular_map = Ref<Texture2D>(), const Color &p_specular_color_shininess = Color(1, 1, 1, 1), TextureFilter p_texture_filter = TEXTURE_FILTER_PARENT_NODE, TextureRepeat p_texture_repeat = TEXTURE_REPEAT_PARENT_NODE);
-
-	void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
-	float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));
-
-	void draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale);
-	void draw_set_transform_matrix(const Transform2D &p_matrix);
-
-	static CanvasItem *get_current_item_drawn();
-
-	/* RECT / TRANSFORM */
-
-	void set_as_toplevel(bool p_toplevel);
-	bool is_set_as_toplevel() const;
-
-	void set_draw_behind_parent(bool p_enable);
-	bool is_draw_behind_parent_enabled() const;
-
-	CanvasItem *get_parent_item() const;
-
-	virtual Transform2D get_transform() const = 0;
-
-	virtual Transform2D get_global_transform() const;
-	virtual Transform2D get_global_transform_with_canvas() const;
-	virtual Transform2D get_screen_transform() const;
-
-	CanvasItem *get_toplevel() const;
-	_FORCE_INLINE_ RID get_canvas_item() const {
-		return canvas_item;
-	}
-
-	void set_block_transform_notify(bool p_enable);
-	bool is_block_transform_notify_enabled() const;
-
-	Transform2D get_canvas_transform() const;
-	Transform2D get_viewport_transform() const;
-	Rect2 get_viewport_rect() const;
-	RID get_viewport_rid() const;
-	RID get_canvas() const;
-	ObjectID get_canvas_layer_instance_id() const;
-	Ref<World2D> get_world_2d() const;
-
-	virtual void set_material(const Ref<Material> &p_material);
-	Ref<Material> get_material() const;
-
-	virtual void set_use_parent_material(bool p_use_parent_material);
-	bool get_use_parent_material() const;
-
-	Ref<InputEvent> make_input_local(const Ref<InputEvent> &p_event) const;
-	Vector2 make_canvas_position_local(const Vector2 &screen_point) const;
-
-	Vector2 get_global_mouse_position() const;
-	Vector2 get_local_mouse_position() const;
-
-	void set_notify_local_transform(bool p_enable);
-	bool is_local_transform_notification_enabled() const;
-
-	void set_notify_transform(bool p_enable);
-	bool is_transform_notification_enabled() const;
-
-	void force_update_transform();
-
-	void set_texture_filter(TextureFilter p_texture_filter);
-	TextureFilter get_texture_filter() const;
-
-	void set_texture_repeat(TextureRepeat p_texture_repeat);
-	TextureRepeat get_texture_repeat() const;
-
-	// Used by control nodes to retrieve the parent's anchorable area
-	virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
-
-	int get_canvas_layer() const;
-
-	CanvasItem();
-	~CanvasItem();
-};
-
-VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
-VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
-
-#endif // CANVAS_ITEM_H
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 3b8a81d2ca..8678e5a1f4 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -31,8 +31,8 @@
 #include "cpu_particles_2d.h"
 
 #include "core/core_string_names.h"
-#include "scene/2d/canvas_item.h"
-#include "scene/2d/particles_2d.h"
+#include "scene/2d/gpu_particles_2d.h"
+#include "scene/main/canvas_item.h"
 #include "scene/resources/particles_material.h"
 #include "servers/visual_server.h"
 
@@ -1144,7 +1144,7 @@ void CPUParticles2D::_notification(int p_what) {
 
 void CPUParticles2D::convert_from_particles(Node *p_particles) {
 
-	Particles2D *particles = Object::cast_to<Particles2D>(p_particles);
+	GPUParticles2D *particles = Object::cast_to<GPUParticles2D>(p_particles);
 	ERR_FAIL_COND_MSG(!particles, "Only Particles2D nodes can be converted to CPUParticles2D.");
 
 	set_emitting(particles->is_emitting());
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
new file mode 100644
index 0000000000..d3d1326018
--- /dev/null
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -0,0 +1,432 @@
+/*************************************************************************/
+/*  gpu_particles_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 "gpu_particles_2d.h"
+
+#include "core/os/os.h"
+#include "scene/resources/particles_material.h"
+#include "scene/scene_string_names.h"
+
+#ifdef TOOLS_ENABLED
+#include "core/engine.h"
+#endif
+
+void GPUParticles2D::set_emitting(bool p_emitting) {
+
+	VS::get_singleton()->particles_set_emitting(particles, p_emitting);
+
+	if (p_emitting && one_shot) {
+		set_process_internal(true);
+	} else if (!p_emitting) {
+		set_process_internal(false);
+	}
+}
+
+void GPUParticles2D::set_amount(int p_amount) {
+
+	ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
+	amount = p_amount;
+	VS::get_singleton()->particles_set_amount(particles, amount);
+}
+void GPUParticles2D::set_lifetime(float p_lifetime) {
+
+	ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
+	lifetime = p_lifetime;
+	VS::get_singleton()->particles_set_lifetime(particles, lifetime);
+}
+
+void GPUParticles2D::set_one_shot(bool p_enable) {
+
+	one_shot = p_enable;
+	VS::get_singleton()->particles_set_one_shot(particles, one_shot);
+
+	if (is_emitting()) {
+
+		set_process_internal(true);
+		if (!one_shot)
+			VisualServer::get_singleton()->particles_restart(particles);
+	}
+
+	if (!one_shot)
+		set_process_internal(false);
+}
+void GPUParticles2D::set_pre_process_time(float p_time) {
+
+	pre_process_time = p_time;
+	VS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
+}
+void GPUParticles2D::set_explosiveness_ratio(float p_ratio) {
+
+	explosiveness_ratio = p_ratio;
+	VS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
+}
+void GPUParticles2D::set_randomness_ratio(float p_ratio) {
+
+	randomness_ratio = p_ratio;
+	VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
+}
+void GPUParticles2D::set_visibility_rect(const Rect2 &p_visibility_rect) {
+
+	visibility_rect = p_visibility_rect;
+	AABB aabb;
+	aabb.position.x = p_visibility_rect.position.x;
+	aabb.position.y = p_visibility_rect.position.y;
+	aabb.size.x = p_visibility_rect.size.x;
+	aabb.size.y = p_visibility_rect.size.y;
+
+	VS::get_singleton()->particles_set_custom_aabb(particles, aabb);
+
+	_change_notify("visibility_rect");
+	update();
+}
+void GPUParticles2D::set_use_local_coordinates(bool p_enable) {
+
+	local_coords = p_enable;
+	VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
+	set_notify_transform(!p_enable);
+	if (!p_enable && is_inside_tree()) {
+		_update_particle_emission_transform();
+	}
+}
+
+void GPUParticles2D::_update_particle_emission_transform() {
+
+	Transform2D xf2d = get_global_transform();
+	Transform xf;
+	xf.basis.set_axis(0, Vector3(xf2d.get_axis(0).x, xf2d.get_axis(0).y, 0));
+	xf.basis.set_axis(1, Vector3(xf2d.get_axis(1).x, xf2d.get_axis(1).y, 0));
+	xf.set_origin(Vector3(xf2d.get_origin().x, xf2d.get_origin().y, 0));
+
+	VS::get_singleton()->particles_set_emission_transform(particles, xf);
+}
+
+void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
+
+	process_material = p_material;
+	Ref<ParticlesMaterial> pm = p_material;
+	if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
+		// Likely a new (3D) material, modify it to match 2D space
+		pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true);
+		pm->set_gravity(Vector3(0, 98, 0));
+	}
+	RID material_rid;
+	if (process_material.is_valid())
+		material_rid = process_material->get_rid();
+	VS::get_singleton()->particles_set_process_material(particles, material_rid);
+
+	update_configuration_warning();
+}
+
+void GPUParticles2D::set_speed_scale(float p_scale) {
+
+	speed_scale = p_scale;
+	VS::get_singleton()->particles_set_speed_scale(particles, p_scale);
+}
+
+bool GPUParticles2D::is_emitting() const {
+
+	return VS::get_singleton()->particles_get_emitting(particles);
+}
+int GPUParticles2D::get_amount() const {
+
+	return amount;
+}
+float GPUParticles2D::get_lifetime() const {
+
+	return lifetime;
+}
+
+bool GPUParticles2D::get_one_shot() const {
+
+	return one_shot;
+}
+float GPUParticles2D::get_pre_process_time() const {
+
+	return pre_process_time;
+}
+float GPUParticles2D::get_explosiveness_ratio() const {
+
+	return explosiveness_ratio;
+}
+float GPUParticles2D::get_randomness_ratio() const {
+
+	return randomness_ratio;
+}
+Rect2 GPUParticles2D::get_visibility_rect() const {
+
+	return visibility_rect;
+}
+bool GPUParticles2D::get_use_local_coordinates() const {
+
+	return local_coords;
+}
+Ref<Material> GPUParticles2D::get_process_material() const {
+
+	return process_material;
+}
+
+float GPUParticles2D::get_speed_scale() const {
+
+	return speed_scale;
+}
+
+void GPUParticles2D::set_draw_order(DrawOrder p_order) {
+
+	draw_order = p_order;
+	VS::get_singleton()->particles_set_draw_order(particles, VS::ParticlesDrawOrder(p_order));
+}
+
+GPUParticles2D::DrawOrder GPUParticles2D::get_draw_order() const {
+
+	return draw_order;
+}
+
+void GPUParticles2D::set_fixed_fps(int p_count) {
+	fixed_fps = p_count;
+	VS::get_singleton()->particles_set_fixed_fps(particles, p_count);
+}
+
+int GPUParticles2D::get_fixed_fps() const {
+	return fixed_fps;
+}
+
+void GPUParticles2D::set_fractional_delta(bool p_enable) {
+	fractional_delta = p_enable;
+	VS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
+}
+
+bool GPUParticles2D::get_fractional_delta() const {
+	return fractional_delta;
+}
+
+String GPUParticles2D::get_configuration_warning() const {
+
+	if (VisualServer::get_singleton()->is_low_end()) {
+		return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles\" option for this purpose.");
+	}
+
+	String warnings;
+
+	if (process_material.is_null()) {
+		if (warnings != String())
+			warnings += "\n";
+		warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
+	} else {
+
+		CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
+
+		if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
+			const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
+			if (process &&
+					(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
+							process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
+				if (warnings != String())
+					warnings += "\n";
+				warnings += "- " + TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
+			}
+		}
+	}
+
+	return warnings;
+}
+
+Rect2 GPUParticles2D::capture_rect() const {
+
+	AABB aabb = VS::get_singleton()->particles_get_current_aabb(particles);
+	Rect2 r;
+	r.position.x = aabb.position.x;
+	r.position.y = aabb.position.y;
+	r.size.x = aabb.size.x;
+	r.size.y = aabb.size.y;
+	return r;
+}
+
+void GPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) {
+	texture = p_texture;
+	update();
+}
+
+Ref<Texture2D> GPUParticles2D::get_texture() const {
+	return texture;
+}
+
+void GPUParticles2D::set_normal_map(const Ref<Texture2D> &p_normal_map) {
+
+	normal_map = p_normal_map;
+	update();
+}
+
+Ref<Texture2D> GPUParticles2D::get_normal_map() const {
+	return normal_map;
+}
+
+void GPUParticles2D::_validate_property(PropertyInfo &property) const {
+}
+
+void GPUParticles2D::restart() {
+	VS::get_singleton()->particles_restart(particles);
+	VS::get_singleton()->particles_set_emitting(particles, true);
+}
+
+void GPUParticles2D::_notification(int p_what) {
+
+	if (p_what == NOTIFICATION_DRAW) {
+
+		RID texture_rid;
+		if (texture.is_valid())
+			texture_rid = texture->get_rid();
+		RID normal_rid;
+		if (normal_map.is_valid())
+			normal_rid = normal_map->get_rid();
+
+		VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid);
+
+#ifdef TOOLS_ENABLED
+		if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) {
+
+			draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false);
+		}
+#endif
+	}
+
+	if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
+		if (can_process()) {
+			VS::get_singleton()->particles_set_speed_scale(particles, speed_scale);
+		} else {
+
+			VS::get_singleton()->particles_set_speed_scale(particles, 0);
+		}
+	}
+
+	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
+		_update_particle_emission_transform();
+	}
+
+	if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+
+		if (one_shot && !is_emitting()) {
+			_change_notify();
+			set_process_internal(false);
+		}
+	}
+}
+
+void GPUParticles2D::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &GPUParticles2D::set_emitting);
+	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &GPUParticles2D::set_amount);
+	ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &GPUParticles2D::set_lifetime);
+	ClassDB::bind_method(D_METHOD("set_one_shot", "secs"), &GPUParticles2D::set_one_shot);
+	ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &GPUParticles2D::set_pre_process_time);
+	ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &GPUParticles2D::set_explosiveness_ratio);
+	ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &GPUParticles2D::set_randomness_ratio);
+	ClassDB::bind_method(D_METHOD("set_visibility_rect", "visibility_rect"), &GPUParticles2D::set_visibility_rect);
+	ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &GPUParticles2D::set_use_local_coordinates);
+	ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &GPUParticles2D::set_fixed_fps);
+	ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles2D::set_fractional_delta);
+	ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles2D::set_process_material);
+	ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles2D::set_speed_scale);
+
+	ClassDB::bind_method(D_METHOD("is_emitting"), &GPUParticles2D::is_emitting);
+	ClassDB::bind_method(D_METHOD("get_amount"), &GPUParticles2D::get_amount);
+	ClassDB::bind_method(D_METHOD("get_lifetime"), &GPUParticles2D::get_lifetime);
+	ClassDB::bind_method(D_METHOD("get_one_shot"), &GPUParticles2D::get_one_shot);
+	ClassDB::bind_method(D_METHOD("get_pre_process_time"), &GPUParticles2D::get_pre_process_time);
+	ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &GPUParticles2D::get_explosiveness_ratio);
+	ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &GPUParticles2D::get_randomness_ratio);
+	ClassDB::bind_method(D_METHOD("get_visibility_rect"), &GPUParticles2D::get_visibility_rect);
+	ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &GPUParticles2D::get_use_local_coordinates);
+	ClassDB::bind_method(D_METHOD("get_fixed_fps"), &GPUParticles2D::get_fixed_fps);
+	ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles2D::get_fractional_delta);
+	ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles2D::get_process_material);
+	ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles2D::get_speed_scale);
+
+	ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &GPUParticles2D::set_draw_order);
+	ClassDB::bind_method(D_METHOD("get_draw_order"), &GPUParticles2D::get_draw_order);
+
+	ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticles2D::set_texture);
+	ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticles2D::get_texture);
+
+	ClassDB::bind_method(D_METHOD("set_normal_map", "texture"), &GPUParticles2D::set_normal_map);
+	ClassDB::bind_method(D_METHOD("get_normal_map"), &GPUParticles2D::get_normal_map);
+
+	ClassDB::bind_method(D_METHOD("capture_rect"), &GPUParticles2D::capture_rect);
+
+	ClassDB::bind_method(D_METHOD("restart"), &GPUParticles2D::restart);
+
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
+	ADD_GROUP("Time", "");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+	ADD_GROUP("Drawing", "");
+	ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order");
+	ADD_GROUP("Process Material", "process_");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
+	ADD_GROUP("Textures", "");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map");
+
+	BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
+	BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
+}
+
+GPUParticles2D::GPUParticles2D() {
+
+	particles = VS::get_singleton()->particles_create();
+
+	one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
+	set_emitting(true);
+	set_one_shot(false);
+	set_amount(8);
+	set_lifetime(1);
+	set_fixed_fps(0);
+	set_fractional_delta(true);
+	set_pre_process_time(0);
+	set_explosiveness_ratio(0);
+	set_randomness_ratio(0);
+	set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
+	set_use_local_coordinates(true);
+	set_draw_order(DRAW_ORDER_INDEX);
+	set_speed_scale(1);
+}
+
+GPUParticles2D::~GPUParticles2D() {
+
+	VS::get_singleton()->free(particles);
+}
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
new file mode 100644
index 0000000000..47951d76dc
--- /dev/null
+++ b/scene/2d/gpu_particles_2d.h
@@ -0,0 +1,127 @@
+/*************************************************************************/
+/*  gpu_particles_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 PARTICLES_2D_H
+#define PARTICLES_2D_H
+
+#include "core/rid.h"
+#include "scene/2d/node_2d.h"
+#include "scene/resources/texture.h"
+
+class GPUParticles2D : public Node2D {
+private:
+	GDCLASS(GPUParticles2D, Node2D);
+
+public:
+	enum DrawOrder {
+		DRAW_ORDER_INDEX,
+		DRAW_ORDER_LIFETIME,
+	};
+
+private:
+	RID particles;
+
+	bool one_shot;
+	int amount;
+	float lifetime;
+	float pre_process_time;
+	float explosiveness_ratio;
+	float randomness_ratio;
+	float speed_scale;
+	Rect2 visibility_rect;
+	bool local_coords;
+	int fixed_fps;
+	bool fractional_delta;
+
+	Ref<Material> process_material;
+
+	DrawOrder draw_order;
+
+	Ref<Texture2D> texture;
+	Ref<Texture2D> normal_map;
+
+	void _update_particle_emission_transform();
+
+protected:
+	static void _bind_methods();
+	virtual void _validate_property(PropertyInfo &property) const;
+	void _notification(int p_what);
+
+public:
+	void set_emitting(bool p_emitting);
+	void set_amount(int p_amount);
+	void set_lifetime(float p_lifetime);
+	void set_one_shot(bool p_enable);
+	void set_pre_process_time(float p_time);
+	void set_explosiveness_ratio(float p_ratio);
+	void set_randomness_ratio(float p_ratio);
+	void set_visibility_rect(const Rect2 &p_visibility_rect);
+	void set_use_local_coordinates(bool p_enable);
+	void set_process_material(const Ref<Material> &p_material);
+	void set_speed_scale(float p_scale);
+
+	bool is_emitting() const;
+	int get_amount() const;
+	float get_lifetime() const;
+	bool get_one_shot() const;
+	float get_pre_process_time() const;
+	float get_explosiveness_ratio() const;
+	float get_randomness_ratio() const;
+	Rect2 get_visibility_rect() const;
+	bool get_use_local_coordinates() const;
+	Ref<Material> get_process_material() const;
+	float get_speed_scale() const;
+
+	void set_fixed_fps(int p_count);
+	int get_fixed_fps() const;
+
+	void set_fractional_delta(bool p_enable);
+	bool get_fractional_delta() const;
+
+	void set_draw_order(DrawOrder p_order);
+	DrawOrder get_draw_order() const;
+
+	void set_texture(const Ref<Texture2D> &p_texture);
+	Ref<Texture2D> get_texture() const;
+
+	void set_normal_map(const Ref<Texture2D> &p_normal_map);
+	Ref<Texture2D> get_normal_map() const;
+
+	virtual String get_configuration_warning() const;
+
+	void restart();
+	Rect2 capture_rect() const;
+	GPUParticles2D();
+	~GPUParticles2D();
+};
+
+VARIANT_ENUM_CAST(GPUParticles2D::DrawOrder)
+
+#endif // PARTICLES_2D_H
diff --git a/scene/2d/navigation_2d.h b/scene/2d/navigation_2d.h
index 5520f5006e..1da13fc78a 100644
--- a/scene/2d/navigation_2d.h
+++ b/scene/2d/navigation_2d.h
@@ -31,7 +31,7 @@
 #ifndef NAVIGATION_2D_H
 #define NAVIGATION_2D_H
 
-#include "scene/2d/navigation_polygon.h"
+#include "scene/2d/navigation_region_2d.h"
 #include "scene/2d/node_2d.h"
 
 class Navigation2D : public Node2D {
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
deleted file mode 100644
index 9159ef21c5..0000000000
--- a/scene/2d/navigation_polygon.cpp
+++ /dev/null
@@ -1,582 +0,0 @@
-/*************************************************************************/
-/*  navigation_polygon.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 "navigation_polygon.h"
-
-#include "core/core_string_names.h"
-#include "core/engine.h"
-#include "core/os/mutex.h"
-#include "navigation_2d.h"
-#include "servers/navigation_2d_server.h"
-
-#include "thirdparty/misc/triangulator.h"
-
-#ifdef TOOLS_ENABLED
-Rect2 NavigationPolygon::_edit_get_rect() const {
-
-	if (rect_cache_dirty) {
-		item_rect = Rect2();
-		bool first = true;
-
-		for (int i = 0; i < outlines.size(); i++) {
-			const Vector<Vector2> &outline = outlines[i];
-			const int outline_size = outline.size();
-			if (outline_size < 3)
-				continue;
-			const Vector2 *p = outline.ptr();
-			for (int j = 0; j < outline_size; j++) {
-				if (first) {
-					item_rect = Rect2(p[j], Vector2(0, 0));
-					first = false;
-				} else {
-					item_rect.expand_to(p[j]);
-				}
-			}
-		}
-
-		rect_cache_dirty = false;
-	}
-	return item_rect;
-}
-
-bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
-
-	for (int i = 0; i < outlines.size(); i++) {
-		const Vector<Vector2> &outline = outlines[i];
-		const int outline_size = outline.size();
-		if (outline_size < 3)
-			continue;
-		if (Geometry::is_point_in_polygon(p_point, Variant(outline)))
-			return true;
-	}
-	return false;
-}
-#endif
-
-void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) {
-
-	{
-		MutexLock lock(navmesh_generation);
-		navmesh.unref();
-	}
-	vertices = p_vertices;
-	rect_cache_dirty = true;
-}
-
-Vector<Vector2> NavigationPolygon::get_vertices() const {
-
-	return vertices;
-}
-
-void NavigationPolygon::_set_polygons(const Array &p_array) {
-
-	{
-		MutexLock lock(navmesh_generation);
-		navmesh.unref();
-	}
-	polygons.resize(p_array.size());
-	for (int i = 0; i < p_array.size(); i++) {
-		polygons.write[i].indices = p_array[i];
-	}
-}
-
-Array NavigationPolygon::_get_polygons() const {
-
-	Array ret;
-	ret.resize(polygons.size());
-	for (int i = 0; i < ret.size(); i++) {
-		ret[i] = polygons[i].indices;
-	}
-
-	return ret;
-}
-
-void NavigationPolygon::_set_outlines(const Array &p_array) {
-
-	outlines.resize(p_array.size());
-	for (int i = 0; i < p_array.size(); i++) {
-		outlines.write[i] = p_array[i];
-	}
-	rect_cache_dirty = true;
-}
-
-Array NavigationPolygon::_get_outlines() const {
-
-	Array ret;
-	ret.resize(outlines.size());
-	for (int i = 0; i < ret.size(); i++) {
-		ret[i] = outlines[i];
-	}
-
-	return ret;
-}
-
-void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {
-
-	Polygon polygon;
-	polygon.indices = p_polygon;
-	polygons.push_back(polygon);
-	{
-		MutexLock lock(navmesh_generation);
-		navmesh.unref();
-	}
-}
-
-void NavigationPolygon::add_outline_at_index(const Vector<Vector2> &p_outline, int p_index) {
-
-	outlines.insert(p_index, p_outline);
-	rect_cache_dirty = true;
-}
-
-int NavigationPolygon::get_polygon_count() const {
-
-	return polygons.size();
-}
-Vector<int> NavigationPolygon::get_polygon(int p_idx) {
-
-	ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>());
-	return polygons[p_idx].indices;
-}
-void NavigationPolygon::clear_polygons() {
-
-	polygons.clear();
-	{
-		MutexLock lock(navmesh_generation);
-		navmesh.unref();
-	}
-}
-
-Ref<NavigationMesh> NavigationPolygon::get_mesh() {
-	MutexLock lock(navmesh_generation);
-
-	if (navmesh.is_null()) {
-		navmesh.instance();
-		Vector<Vector3> verts;
-		{
-			verts.resize(get_vertices().size());
-			Vector3 *w = verts.ptrw();
-
-			const Vector2 *r = get_vertices().ptr();
-
-			for (int i(0); i < get_vertices().size(); i++) {
-				w[i] = Vector3(r[i].x, 0.0, r[i].y);
-			}
-		}
-		navmesh->set_vertices(verts);
-
-		for (int i(0); i < get_polygon_count(); i++) {
-			navmesh->add_polygon(get_polygon(i));
-		}
-	}
-
-	return navmesh;
-}
-
-void NavigationPolygon::add_outline(const Vector<Vector2> &p_outline) {
-
-	outlines.push_back(p_outline);
-	rect_cache_dirty = true;
-}
-
-int NavigationPolygon::get_outline_count() const {
-
-	return outlines.size();
-}
-
-void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) {
-	ERR_FAIL_INDEX(p_idx, outlines.size());
-	outlines.write[p_idx] = p_outline;
-	rect_cache_dirty = true;
-}
-
-void NavigationPolygon::remove_outline(int p_idx) {
-
-	ERR_FAIL_INDEX(p_idx, outlines.size());
-	outlines.remove(p_idx);
-	rect_cache_dirty = true;
-}
-
-Vector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
-	ERR_FAIL_INDEX_V(p_idx, outlines.size(), Vector<Vector2>());
-	return outlines[p_idx];
-}
-
-void NavigationPolygon::clear_outlines() {
-
-	outlines.clear();
-	rect_cache_dirty = true;
-}
-void NavigationPolygon::make_polygons_from_outlines() {
-
-	{
-		MutexLock lock(navmesh_generation);
-		navmesh.unref();
-	}
-	List<TriangulatorPoly> in_poly, out_poly;
-
-	Vector2 outside_point(-1e10, -1e10);
-
-	for (int i = 0; i < outlines.size(); i++) {
-
-		Vector<Vector2> ol = outlines[i];
-		int olsize = ol.size();
-		if (olsize < 3)
-			continue;
-		const Vector2 *r = ol.ptr();
-		for (int j = 0; j < olsize; j++) {
-			outside_point.x = MAX(r[j].x, outside_point.x);
-			outside_point.y = MAX(r[j].y, outside_point.y);
-		}
-	}
-
-	outside_point += Vector2(0.7239784, 0.819238); //avoid precision issues
-
-	for (int i = 0; i < outlines.size(); i++) {
-
-		Vector<Vector2> ol = outlines[i];
-		int olsize = ol.size();
-		if (olsize < 3)
-			continue;
-		const Vector2 *r = ol.ptr();
-
-		int interscount = 0;
-		//test if this is an outer outline
-		for (int k = 0; k < outlines.size(); k++) {
-
-			if (i == k)
-				continue; //no self intersect
-
-			Vector<Vector2> ol2 = outlines[k];
-			int olsize2 = ol2.size();
-			if (olsize2 < 3)
-				continue;
-			const Vector2 *r2 = ol2.ptr();
-
-			for (int l = 0; l < olsize2; l++) {
-
-				if (Geometry::segment_intersects_segment_2d(r[0], outside_point, r2[l], r2[(l + 1) % olsize2], NULL)) {
-					interscount++;
-				}
-			}
-		}
-
-		bool outer = (interscount % 2) == 0;
-
-		TriangulatorPoly tp;
-		tp.Init(olsize);
-		for (int j = 0; j < olsize; j++) {
-			tp[j] = r[j];
-		}
-
-		if (outer)
-			tp.SetOrientation(TRIANGULATOR_CCW);
-		else {
-			tp.SetOrientation(TRIANGULATOR_CW);
-			tp.SetHole(true);
-		}
-
-		in_poly.push_back(tp);
-	}
-
-	TriangulatorPartition tpart;
-	if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
-		ERR_PRINT("NavigationPolygon: Convex partition failed!");
-		return;
-	}
-
-	polygons.clear();
-	vertices.resize(0);
-
-	Map<Vector2, int> points;
-	for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) {
-
-		TriangulatorPoly &tp = I->get();
-
-		struct Polygon p;
-
-		for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
-
-			Map<Vector2, int>::Element *E = points.find(tp[i]);
-			if (!E) {
-				E = points.insert(tp[i], vertices.size());
-				vertices.push_back(tp[i]);
-			}
-			p.indices.push_back(E->get());
-		}
-
-		polygons.push_back(p);
-	}
-
-	emit_signal(CoreStringNames::get_singleton()->changed);
-}
-
-void NavigationPolygon::_bind_methods() {
-
-	ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices);
-	ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices);
-
-	ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationPolygon::add_polygon);
-	ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count);
-	ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon);
-	ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons);
-
-	ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline);
-	ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index);
-	ClassDB::bind_method(D_METHOD("get_outline_count"), &NavigationPolygon::get_outline_count);
-	ClassDB::bind_method(D_METHOD("set_outline", "idx", "outline"), &NavigationPolygon::set_outline);
-	ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline);
-	ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline);
-	ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines);
-	ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines);
-
-	ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons);
-	ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons);
-
-	ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines);
-	ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines);
-
-	ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
-	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
-	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
-}
-
-NavigationPolygon::NavigationPolygon() :
-		rect_cache_dirty(true) {
-}
-
-NavigationPolygon::~NavigationPolygon() {
-}
-
-void NavigationRegion2D::set_enabled(bool p_enabled) {
-
-	if (enabled == p_enabled)
-		return;
-	enabled = p_enabled;
-
-	if (!is_inside_tree())
-		return;
-
-	if (!enabled) {
-
-		Navigation2DServer::get_singleton()->region_set_map(region, RID());
-	} else {
-
-		if (navigation) {
-
-			Navigation2DServer::get_singleton()->region_set_map(region, navigation->get_rid());
-		}
-	}
-
-	if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())
-		update();
-}
-
-bool NavigationRegion2D::is_enabled() const {
-
-	return enabled;
-}
-
-/////////////////////////////
-#ifdef TOOLS_ENABLED
-Rect2 NavigationRegion2D::_edit_get_rect() const {
-
-	return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
-}
-
-bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
-
-	return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false;
-}
-#endif
-
-void NavigationRegion2D::_notification(int p_what) {
-
-	switch (p_what) {
-		case NOTIFICATION_ENTER_TREE: {
-
-			Node2D *c = this;
-			while (c) {
-
-				navigation = Object::cast_to<Navigation2D>(c);
-				if (navigation) {
-
-					if (enabled) {
-
-						Navigation2DServer::get_singleton()->region_set_map(region, navigation->get_rid());
-					}
-					break;
-				}
-
-				c = Object::cast_to<Node2D>(c->get_parent());
-			}
-
-		} break;
-		case NOTIFICATION_TRANSFORM_CHANGED: {
-
-			Navigation2DServer::get_singleton()->region_set_transform(region, get_global_transform());
-
-		} break;
-		case NOTIFICATION_EXIT_TREE: {
-
-			if (navigation) {
-
-				Navigation2DServer::get_singleton()->region_set_map(region, RID());
-			}
-			navigation = NULL;
-		} break;
-		case NOTIFICATION_DRAW: {
-
-			if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) {
-
-				Vector<Vector2> verts = navpoly->get_vertices();
-				int vsize = verts.size();
-				if (vsize < 3)
-					return;
-
-				Color color;
-				if (enabled) {
-					color = get_tree()->get_debug_navigation_color();
-				} else {
-					color = get_tree()->get_debug_navigation_disabled_color();
-				}
-				Vector<Color> colors;
-				Vector<Vector2> vertices;
-				vertices.resize(vsize);
-				colors.resize(vsize);
-				{
-					const Vector2 *vr = verts.ptr();
-					for (int i = 0; i < vsize; i++) {
-						vertices.write[i] = vr[i];
-						colors.write[i] = color;
-					}
-				}
-
-				Vector<int> indices;
-
-				for (int i = 0; i < navpoly->get_polygon_count(); i++) {
-					Vector<int> polygon = navpoly->get_polygon(i);
-
-					for (int j = 2; j < polygon.size(); j++) {
-
-						int kofs[3] = { 0, j - 1, j };
-						for (int k = 0; k < 3; k++) {
-
-							int idx = polygon[kofs[k]];
-							ERR_FAIL_INDEX(idx, vsize);
-							indices.push_back(idx);
-						}
-					}
-				}
-				VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, vertices, colors);
-			}
-		} break;
-	}
-}
-
-void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly) {
-
-	if (p_navpoly == navpoly) {
-		return;
-	}
-
-	if (navpoly.is_valid()) {
-		navpoly->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
-	}
-
-	navpoly = p_navpoly;
-	Navigation2DServer::get_singleton()->region_set_navpoly(region, p_navpoly);
-
-	if (navpoly.is_valid()) {
-		navpoly->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
-	}
-	_navpoly_changed();
-
-	_change_notify("navpoly");
-	update_configuration_warning();
-}
-
-Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
-
-	return navpoly;
-}
-
-void NavigationRegion2D::_navpoly_changed() {
-
-	if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()))
-		update();
-}
-
-String NavigationRegion2D::get_configuration_warning() const {
-
-	if (!is_visible_in_tree() || !is_inside_tree())
-		return String();
-
-	if (!navpoly.is_valid()) {
-		return TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon.");
-	}
-	const Node2D *c = this;
-	while (c) {
-
-		if (Object::cast_to<Navigation2D>(c)) {
-			return String();
-		}
-
-		c = Object::cast_to<Node2D>(c->get_parent());
-	}
-
-	return TTR("NavigationRegion2D must be a child or grandchild to a Navigation2D node. It only provides navigation data.");
-}
-
-void NavigationRegion2D::_bind_methods() {
-
-	ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navpoly"), &NavigationRegion2D::set_navigation_polygon);
-	ClassDB::bind_method(D_METHOD("get_navigation_polygon"), &NavigationRegion2D::get_navigation_polygon);
-
-	ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion2D::set_enabled);
-	ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion2D::is_enabled);
-
-	ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed);
-
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
-}
-
-NavigationRegion2D::NavigationRegion2D() {
-
-	enabled = true;
-	set_notify_transform(true);
-	region = Navigation2DServer::get_singleton()->region_create();
-
-	navigation = NULL;
-}
-
-NavigationRegion2D::~NavigationRegion2D() {
-	Navigation2DServer::get_singleton()->free(region);
-}
diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h
deleted file mode 100644
index 3d096ec91b..0000000000
--- a/scene/2d/navigation_polygon.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*************************************************************************/
-/*  navigation_polygon.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 NAVIGATION_POLYGON_H
-#define NAVIGATION_POLYGON_H
-
-#include "scene/2d/node_2d.h"
-#include "scene/resources/navigation_mesh.h"
-
-class NavigationPolygon : public Resource {
-
-	GDCLASS(NavigationPolygon, Resource);
-
-	Vector<Vector2> vertices;
-	struct Polygon {
-		Vector<int> indices;
-	};
-	Vector<Polygon> polygons;
-	Vector<Vector<Vector2>> outlines;
-
-	mutable Rect2 item_rect;
-	mutable bool rect_cache_dirty;
-
-	Mutex navmesh_generation;
-	// Navigation mesh
-	Ref<NavigationMesh> navmesh;
-
-protected:
-	static void _bind_methods();
-
-	void _set_polygons(const Array &p_array);
-	Array _get_polygons() const;
-
-	void _set_outlines(const Array &p_array);
-	Array _get_outlines() const;
-
-public:
-#ifdef TOOLS_ENABLED
-	Rect2 _edit_get_rect() const;
-	bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-#endif
-
-	void set_vertices(const Vector<Vector2> &p_vertices);
-	Vector<Vector2> get_vertices() const;
-
-	void add_polygon(const Vector<int> &p_polygon);
-	int get_polygon_count() const;
-
-	void add_outline(const Vector<Vector2> &p_outline);
-	void add_outline_at_index(const Vector<Vector2> &p_outline, int p_index);
-	void set_outline(int p_idx, const Vector<Vector2> &p_outline);
-	Vector<Vector2> get_outline(int p_idx) const;
-	void remove_outline(int p_idx);
-	int get_outline_count() const;
-
-	void clear_outlines();
-	void make_polygons_from_outlines();
-
-	Vector<int> get_polygon(int p_idx);
-	void clear_polygons();
-
-	Ref<NavigationMesh> get_mesh();
-
-	NavigationPolygon();
-	~NavigationPolygon();
-};
-
-class Navigation2D;
-
-class NavigationRegion2D : public Node2D {
-
-	GDCLASS(NavigationRegion2D, Node2D);
-
-	bool enabled;
-	RID region;
-	Navigation2D *navigation;
-	Ref<NavigationPolygon> navpoly;
-
-	void _navpoly_changed();
-
-protected:
-	void _notification(int p_what);
-	static void _bind_methods();
-
-public:
-#ifdef TOOLS_ENABLED
-	virtual Rect2 _edit_get_rect() const;
-	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
-#endif
-
-	void set_enabled(bool p_enabled);
-	bool is_enabled() const;
-
-	void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
-	Ref<NavigationPolygon> get_navigation_polygon() const;
-
-	String get_configuration_warning() const;
-
-	NavigationRegion2D();
-	~NavigationRegion2D();
-};
-
-#endif // NAVIGATIONPOLYGON_H
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
new file mode 100644
index 0000000000..bc3e305281
--- /dev/null
+++ b/scene/2d/navigation_region_2d.cpp
@@ -0,0 +1,582 @@
+/*************************************************************************/
+/*  navigation_region_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 "navigation_region_2d.h"
+
+#include "core/core_string_names.h"
+#include "core/engine.h"
+#include "core/os/mutex.h"
+#include "navigation_2d.h"
+#include "servers/navigation_2d_server.h"
+
+#include "thirdparty/misc/triangulator.h"
+
+#ifdef TOOLS_ENABLED
+Rect2 NavigationPolygon::_edit_get_rect() const {
+
+	if (rect_cache_dirty) {
+		item_rect = Rect2();
+		bool first = true;
+
+		for (int i = 0; i < outlines.size(); i++) {
+			const Vector<Vector2> &outline = outlines[i];
+			const int outline_size = outline.size();
+			if (outline_size < 3)
+				continue;
+			const Vector2 *p = outline.ptr();
+			for (int j = 0; j < outline_size; j++) {
+				if (first) {
+					item_rect = Rect2(p[j], Vector2(0, 0));
+					first = false;
+				} else {
+					item_rect.expand_to(p[j]);
+				}
+			}
+		}
+
+		rect_cache_dirty = false;
+	}
+	return item_rect;
+}
+
+bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+	for (int i = 0; i < outlines.size(); i++) {
+		const Vector<Vector2> &outline = outlines[i];
+		const int outline_size = outline.size();
+		if (outline_size < 3)
+			continue;
+		if (Geometry::is_point_in_polygon(p_point, Variant(outline)))
+			return true;
+	}
+	return false;
+}
+#endif
+
+void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) {
+
+	{
+		MutexLock lock(navmesh_generation);
+		navmesh.unref();
+	}
+	vertices = p_vertices;
+	rect_cache_dirty = true;
+}
+
+Vector<Vector2> NavigationPolygon::get_vertices() const {
+
+	return vertices;
+}
+
+void NavigationPolygon::_set_polygons(const Array &p_array) {
+
+	{
+		MutexLock lock(navmesh_generation);
+		navmesh.unref();
+	}
+	polygons.resize(p_array.size());
+	for (int i = 0; i < p_array.size(); i++) {
+		polygons.write[i].indices = p_array[i];
+	}
+}
+
+Array NavigationPolygon::_get_polygons() const {
+
+	Array ret;
+	ret.resize(polygons.size());
+	for (int i = 0; i < ret.size(); i++) {
+		ret[i] = polygons[i].indices;
+	}
+
+	return ret;
+}
+
+void NavigationPolygon::_set_outlines(const Array &p_array) {
+
+	outlines.resize(p_array.size());
+	for (int i = 0; i < p_array.size(); i++) {
+		outlines.write[i] = p_array[i];
+	}
+	rect_cache_dirty = true;
+}
+
+Array NavigationPolygon::_get_outlines() const {
+
+	Array ret;
+	ret.resize(outlines.size());
+	for (int i = 0; i < ret.size(); i++) {
+		ret[i] = outlines[i];
+	}
+
+	return ret;
+}
+
+void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {
+
+	Polygon polygon;
+	polygon.indices = p_polygon;
+	polygons.push_back(polygon);
+	{
+		MutexLock lock(navmesh_generation);
+		navmesh.unref();
+	}
+}
+
+void NavigationPolygon::add_outline_at_index(const Vector<Vector2> &p_outline, int p_index) {
+
+	outlines.insert(p_index, p_outline);
+	rect_cache_dirty = true;
+}
+
+int NavigationPolygon::get_polygon_count() const {
+
+	return polygons.size();
+}
+Vector<int> NavigationPolygon::get_polygon(int p_idx) {
+
+	ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>());
+	return polygons[p_idx].indices;
+}
+void NavigationPolygon::clear_polygons() {
+
+	polygons.clear();
+	{
+		MutexLock lock(navmesh_generation);
+		navmesh.unref();
+	}
+}
+
+Ref<NavigationMesh> NavigationPolygon::get_mesh() {
+	MutexLock lock(navmesh_generation);
+
+	if (navmesh.is_null()) {
+		navmesh.instance();
+		Vector<Vector3> verts;
+		{
+			verts.resize(get_vertices().size());
+			Vector3 *w = verts.ptrw();
+
+			const Vector2 *r = get_vertices().ptr();
+
+			for (int i(0); i < get_vertices().size(); i++) {
+				w[i] = Vector3(r[i].x, 0.0, r[i].y);
+			}
+		}
+		navmesh->set_vertices(verts);
+
+		for (int i(0); i < get_polygon_count(); i++) {
+			navmesh->add_polygon(get_polygon(i));
+		}
+	}
+
+	return navmesh;
+}
+
+void NavigationPolygon::add_outline(const Vector<Vector2> &p_outline) {
+
+	outlines.push_back(p_outline);
+	rect_cache_dirty = true;
+}
+
+int NavigationPolygon::get_outline_count() const {
+
+	return outlines.size();
+}
+
+void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) {
+	ERR_FAIL_INDEX(p_idx, outlines.size());
+	outlines.write[p_idx] = p_outline;
+	rect_cache_dirty = true;
+}
+
+void NavigationPolygon::remove_outline(int p_idx) {
+
+	ERR_FAIL_INDEX(p_idx, outlines.size());
+	outlines.remove(p_idx);
+	rect_cache_dirty = true;
+}
+
+Vector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
+	ERR_FAIL_INDEX_V(p_idx, outlines.size(), Vector<Vector2>());
+	return outlines[p_idx];
+}
+
+void NavigationPolygon::clear_outlines() {
+
+	outlines.clear();
+	rect_cache_dirty = true;
+}
+void NavigationPolygon::make_polygons_from_outlines() {
+
+	{
+		MutexLock lock(navmesh_generation);
+		navmesh.unref();
+	}
+	List<TriangulatorPoly> in_poly, out_poly;
+
+	Vector2 outside_point(-1e10, -1e10);
+
+	for (int i = 0; i < outlines.size(); i++) {
+
+		Vector<Vector2> ol = outlines[i];
+		int olsize = ol.size();
+		if (olsize < 3)
+			continue;
+		const Vector2 *r = ol.ptr();
+		for (int j = 0; j < olsize; j++) {
+			outside_point.x = MAX(r[j].x, outside_point.x);
+			outside_point.y = MAX(r[j].y, outside_point.y);
+		}
+	}
+
+	outside_point += Vector2(0.7239784, 0.819238); //avoid precision issues
+
+	for (int i = 0; i < outlines.size(); i++) {
+
+		Vector<Vector2> ol = outlines[i];
+		int olsize = ol.size();
+		if (olsize < 3)
+			continue;
+		const Vector2 *r = ol.ptr();
+
+		int interscount = 0;
+		//test if this is an outer outline
+		for (int k = 0; k < outlines.size(); k++) {
+
+			if (i == k)
+				continue; //no self intersect
+
+			Vector<Vector2> ol2 = outlines[k];
+			int olsize2 = ol2.size();
+			if (olsize2 < 3)
+				continue;
+			const Vector2 *r2 = ol2.ptr();
+
+			for (int l = 0; l < olsize2; l++) {
+
+				if (Geometry::segment_intersects_segment_2d(r[0], outside_point, r2[l], r2[(l + 1) % olsize2], NULL)) {
+					interscount++;
+				}
+			}
+		}
+
+		bool outer = (interscount % 2) == 0;
+
+		TriangulatorPoly tp;
+		tp.Init(olsize);
+		for (int j = 0; j < olsize; j++) {
+			tp[j] = r[j];
+		}
+
+		if (outer)
+			tp.SetOrientation(TRIANGULATOR_CCW);
+		else {
+			tp.SetOrientation(TRIANGULATOR_CW);
+			tp.SetHole(true);
+		}
+
+		in_poly.push_back(tp);
+	}
+
+	TriangulatorPartition tpart;
+	if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
+		ERR_PRINT("NavigationPolygon: Convex partition failed!");
+		return;
+	}
+
+	polygons.clear();
+	vertices.resize(0);
+
+	Map<Vector2, int> points;
+	for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) {
+
+		TriangulatorPoly &tp = I->get();
+
+		struct Polygon p;
+
+		for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
+
+			Map<Vector2, int>::Element *E = points.find(tp[i]);
+			if (!E) {
+				E = points.insert(tp[i], vertices.size());
+				vertices.push_back(tp[i]);
+			}
+			p.indices.push_back(E->get());
+		}
+
+		polygons.push_back(p);
+	}
+
+	emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+void NavigationPolygon::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices);
+	ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices);
+
+	ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationPolygon::add_polygon);
+	ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count);
+	ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon);
+	ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons);
+
+	ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline);
+	ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index);
+	ClassDB::bind_method(D_METHOD("get_outline_count"), &NavigationPolygon::get_outline_count);
+	ClassDB::bind_method(D_METHOD("set_outline", "idx", "outline"), &NavigationPolygon::set_outline);
+	ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline);
+	ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline);
+	ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines);
+	ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines);
+
+	ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons);
+	ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons);
+
+	ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines);
+	ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines);
+
+	ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
+}
+
+NavigationPolygon::NavigationPolygon() :
+		rect_cache_dirty(true) {
+}
+
+NavigationPolygon::~NavigationPolygon() {
+}
+
+void NavigationRegion2D::set_enabled(bool p_enabled) {
+
+	if (enabled == p_enabled)
+		return;
+	enabled = p_enabled;
+
+	if (!is_inside_tree())
+		return;
+
+	if (!enabled) {
+
+		Navigation2DServer::get_singleton()->region_set_map(region, RID());
+	} else {
+
+		if (navigation) {
+
+			Navigation2DServer::get_singleton()->region_set_map(region, navigation->get_rid());
+		}
+	}
+
+	if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())
+		update();
+}
+
+bool NavigationRegion2D::is_enabled() const {
+
+	return enabled;
+}
+
+/////////////////////////////
+#ifdef TOOLS_ENABLED
+Rect2 NavigationRegion2D::_edit_get_rect() const {
+
+	return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
+}
+
+bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+	return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false;
+}
+#endif
+
+void NavigationRegion2D::_notification(int p_what) {
+
+	switch (p_what) {
+		case NOTIFICATION_ENTER_TREE: {
+
+			Node2D *c = this;
+			while (c) {
+
+				navigation = Object::cast_to<Navigation2D>(c);
+				if (navigation) {
+
+					if (enabled) {
+
+						Navigation2DServer::get_singleton()->region_set_map(region, navigation->get_rid());
+					}
+					break;
+				}
+
+				c = Object::cast_to<Node2D>(c->get_parent());
+			}
+
+		} break;
+		case NOTIFICATION_TRANSFORM_CHANGED: {
+
+			Navigation2DServer::get_singleton()->region_set_transform(region, get_global_transform());
+
+		} break;
+		case NOTIFICATION_EXIT_TREE: {
+
+			if (navigation) {
+
+				Navigation2DServer::get_singleton()->region_set_map(region, RID());
+			}
+			navigation = NULL;
+		} break;
+		case NOTIFICATION_DRAW: {
+
+			if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) {
+
+				Vector<Vector2> verts = navpoly->get_vertices();
+				int vsize = verts.size();
+				if (vsize < 3)
+					return;
+
+				Color color;
+				if (enabled) {
+					color = get_tree()->get_debug_navigation_color();
+				} else {
+					color = get_tree()->get_debug_navigation_disabled_color();
+				}
+				Vector<Color> colors;
+				Vector<Vector2> vertices;
+				vertices.resize(vsize);
+				colors.resize(vsize);
+				{
+					const Vector2 *vr = verts.ptr();
+					for (int i = 0; i < vsize; i++) {
+						vertices.write[i] = vr[i];
+						colors.write[i] = color;
+					}
+				}
+
+				Vector<int> indices;
+
+				for (int i = 0; i < navpoly->get_polygon_count(); i++) {
+					Vector<int> polygon = navpoly->get_polygon(i);
+
+					for (int j = 2; j < polygon.size(); j++) {
+
+						int kofs[3] = { 0, j - 1, j };
+						for (int k = 0; k < 3; k++) {
+
+							int idx = polygon[kofs[k]];
+							ERR_FAIL_INDEX(idx, vsize);
+							indices.push_back(idx);
+						}
+					}
+				}
+				VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, vertices, colors);
+			}
+		} break;
+	}
+}
+
+void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly) {
+
+	if (p_navpoly == navpoly) {
+		return;
+	}
+
+	if (navpoly.is_valid()) {
+		navpoly->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
+	}
+
+	navpoly = p_navpoly;
+	Navigation2DServer::get_singleton()->region_set_navpoly(region, p_navpoly);
+
+	if (navpoly.is_valid()) {
+		navpoly->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed));
+	}
+	_navpoly_changed();
+
+	_change_notify("navpoly");
+	update_configuration_warning();
+}
+
+Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
+
+	return navpoly;
+}
+
+void NavigationRegion2D::_navpoly_changed() {
+
+	if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()))
+		update();
+}
+
+String NavigationRegion2D::get_configuration_warning() const {
+
+	if (!is_visible_in_tree() || !is_inside_tree())
+		return String();
+
+	if (!navpoly.is_valid()) {
+		return TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon.");
+	}
+	const Node2D *c = this;
+	while (c) {
+
+		if (Object::cast_to<Navigation2D>(c)) {
+			return String();
+		}
+
+		c = Object::cast_to<Node2D>(c->get_parent());
+	}
+
+	return TTR("NavigationRegion2D must be a child or grandchild to a Navigation2D node. It only provides navigation data.");
+}
+
+void NavigationRegion2D::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navpoly"), &NavigationRegion2D::set_navigation_polygon);
+	ClassDB::bind_method(D_METHOD("get_navigation_polygon"), &NavigationRegion2D::get_navigation_polygon);
+
+	ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion2D::set_enabled);
+	ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion2D::is_enabled);
+
+	ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed);
+
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
+}
+
+NavigationRegion2D::NavigationRegion2D() {
+
+	enabled = true;
+	set_notify_transform(true);
+	region = Navigation2DServer::get_singleton()->region_create();
+
+	navigation = NULL;
+}
+
+NavigationRegion2D::~NavigationRegion2D() {
+	Navigation2DServer::get_singleton()->free(region);
+}
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
new file mode 100644
index 0000000000..73e056a353
--- /dev/null
+++ b/scene/2d/navigation_region_2d.h
@@ -0,0 +1,130 @@
+/*************************************************************************/
+/*  navigation_region_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 NAVIGATION_REGION_2D_H
+#define NAVIGATION_REGION_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/resources/navigation_mesh.h"
+
+class NavigationPolygon : public Resource {
+
+	GDCLASS(NavigationPolygon, Resource);
+
+	Vector<Vector2> vertices;
+	struct Polygon {
+		Vector<int> indices;
+	};
+	Vector<Polygon> polygons;
+	Vector<Vector<Vector2>> outlines;
+
+	mutable Rect2 item_rect;
+	mutable bool rect_cache_dirty;
+
+	Mutex navmesh_generation;
+	// Navigation mesh
+	Ref<NavigationMesh> navmesh;
+
+protected:
+	static void _bind_methods();
+
+	void _set_polygons(const Array &p_array);
+	Array _get_polygons() const;
+
+	void _set_outlines(const Array &p_array);
+	Array _get_outlines() const;
+
+public:
+#ifdef TOOLS_ENABLED
+	Rect2 _edit_get_rect() const;
+	bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+#endif
+
+	void set_vertices(const Vector<Vector2> &p_vertices);
+	Vector<Vector2> get_vertices() const;
+
+	void add_polygon(const Vector<int> &p_polygon);
+	int get_polygon_count() const;
+
+	void add_outline(const Vector<Vector2> &p_outline);
+	void add_outline_at_index(const Vector<Vector2> &p_outline, int p_index);
+	void set_outline(int p_idx, const Vector<Vector2> &p_outline);
+	Vector<Vector2> get_outline(int p_idx) const;
+	void remove_outline(int p_idx);
+	int get_outline_count() const;
+
+	void clear_outlines();
+	void make_polygons_from_outlines();
+
+	Vector<int> get_polygon(int p_idx);
+	void clear_polygons();
+
+	Ref<NavigationMesh> get_mesh();
+
+	NavigationPolygon();
+	~NavigationPolygon();
+};
+
+class Navigation2D;
+
+class NavigationRegion2D : public Node2D {
+
+	GDCLASS(NavigationRegion2D, Node2D);
+
+	bool enabled;
+	RID region;
+	Navigation2D *navigation;
+	Ref<NavigationPolygon> navpoly;
+
+	void _navpoly_changed();
+
+protected:
+	void _notification(int p_what);
+	static void _bind_methods();
+
+public:
+#ifdef TOOLS_ENABLED
+	virtual Rect2 _edit_get_rect() const;
+	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+#endif
+
+	void set_enabled(bool p_enabled);
+	bool is_enabled() const;
+
+	void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
+	Ref<NavigationPolygon> get_navigation_polygon() const;
+
+	String get_configuration_warning() const;
+
+	NavigationRegion2D();
+	~NavigationRegion2D();
+};
+
+#endif // NAVIGATION_REGION_2D_H
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 00202481a6..abed05ed0c 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -31,7 +31,7 @@
 #ifndef NODE2D_H
 #define NODE2D_H
 
-#include "scene/2d/canvas_item.h"
+#include "scene/main/canvas_item.h"
 
 class Node2D : public CanvasItem {
 
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
deleted file mode 100644
index e5c17fe9a4..0000000000
--- a/scene/2d/particles_2d.cpp
+++ /dev/null
@@ -1,432 +0,0 @@
-/*************************************************************************/
-/*  particles_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 "particles_2d.h"
-
-#include "core/os/os.h"
-#include "scene/resources/particles_material.h"
-#include "scene/scene_string_names.h"
-
-#ifdef TOOLS_ENABLED
-#include "core/engine.h"
-#endif
-
-void Particles2D::set_emitting(bool p_emitting) {
-
-	VS::get_singleton()->particles_set_emitting(particles, p_emitting);
-
-	if (p_emitting && one_shot) {
-		set_process_internal(true);
-	} else if (!p_emitting) {
-		set_process_internal(false);
-	}
-}
-
-void Particles2D::set_amount(int p_amount) {
-
-	ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
-	amount = p_amount;
-	VS::get_singleton()->particles_set_amount(particles, amount);
-}
-void Particles2D::set_lifetime(float p_lifetime) {
-
-	ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
-	lifetime = p_lifetime;
-	VS::get_singleton()->particles_set_lifetime(particles, lifetime);
-}
-
-void Particles2D::set_one_shot(bool p_enable) {
-
-	one_shot = p_enable;
-	VS::get_singleton()->particles_set_one_shot(particles, one_shot);
-
-	if (is_emitting()) {
-
-		set_process_internal(true);
-		if (!one_shot)
-			VisualServer::get_singleton()->particles_restart(particles);
-	}
-
-	if (!one_shot)
-		set_process_internal(false);
-}
-void Particles2D::set_pre_process_time(float p_time) {
-
-	pre_process_time = p_time;
-	VS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
-}
-void Particles2D::set_explosiveness_ratio(float p_ratio) {
-
-	explosiveness_ratio = p_ratio;
-	VS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
-}
-void Particles2D::set_randomness_ratio(float p_ratio) {
-
-	randomness_ratio = p_ratio;
-	VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
-}
-void Particles2D::set_visibility_rect(const Rect2 &p_visibility_rect) {
-
-	visibility_rect = p_visibility_rect;
-	AABB aabb;
-	aabb.position.x = p_visibility_rect.position.x;
-	aabb.position.y = p_visibility_rect.position.y;
-	aabb.size.x = p_visibility_rect.size.x;
-	aabb.size.y = p_visibility_rect.size.y;
-
-	VS::get_singleton()->particles_set_custom_aabb(particles, aabb);
-
-	_change_notify("visibility_rect");
-	update();
-}
-void Particles2D::set_use_local_coordinates(bool p_enable) {
-
-	local_coords = p_enable;
-	VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
-	set_notify_transform(!p_enable);
-	if (!p_enable && is_inside_tree()) {
-		_update_particle_emission_transform();
-	}
-}
-
-void Particles2D::_update_particle_emission_transform() {
-
-	Transform2D xf2d = get_global_transform();
-	Transform xf;
-	xf.basis.set_axis(0, Vector3(xf2d.get_axis(0).x, xf2d.get_axis(0).y, 0));
-	xf.basis.set_axis(1, Vector3(xf2d.get_axis(1).x, xf2d.get_axis(1).y, 0));
-	xf.set_origin(Vector3(xf2d.get_origin().x, xf2d.get_origin().y, 0));
-
-	VS::get_singleton()->particles_set_emission_transform(particles, xf);
-}
-
-void Particles2D::set_process_material(const Ref<Material> &p_material) {
-
-	process_material = p_material;
-	Ref<ParticlesMaterial> pm = p_material;
-	if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
-		// Likely a new (3D) material, modify it to match 2D space
-		pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true);
-		pm->set_gravity(Vector3(0, 98, 0));
-	}
-	RID material_rid;
-	if (process_material.is_valid())
-		material_rid = process_material->get_rid();
-	VS::get_singleton()->particles_set_process_material(particles, material_rid);
-
-	update_configuration_warning();
-}
-
-void Particles2D::set_speed_scale(float p_scale) {
-
-	speed_scale = p_scale;
-	VS::get_singleton()->particles_set_speed_scale(particles, p_scale);
-}
-
-bool Particles2D::is_emitting() const {
-
-	return VS::get_singleton()->particles_get_emitting(particles);
-}
-int Particles2D::get_amount() const {
-
-	return amount;
-}
-float Particles2D::get_lifetime() const {
-
-	return lifetime;
-}
-
-bool Particles2D::get_one_shot() const {
-
-	return one_shot;
-}
-float Particles2D::get_pre_process_time() const {
-
-	return pre_process_time;
-}
-float Particles2D::get_explosiveness_ratio() const {
-
-	return explosiveness_ratio;
-}
-float Particles2D::get_randomness_ratio() const {
-
-	return randomness_ratio;
-}
-Rect2 Particles2D::get_visibility_rect() const {
-
-	return visibility_rect;
-}
-bool Particles2D::get_use_local_coordinates() const {
-
-	return local_coords;
-}
-Ref<Material> Particles2D::get_process_material() const {
-
-	return process_material;
-}
-
-float Particles2D::get_speed_scale() const {
-
-	return speed_scale;
-}
-
-void Particles2D::set_draw_order(DrawOrder p_order) {
-
-	draw_order = p_order;
-	VS::get_singleton()->particles_set_draw_order(particles, VS::ParticlesDrawOrder(p_order));
-}
-
-Particles2D::DrawOrder Particles2D::get_draw_order() const {
-
-	return draw_order;
-}
-
-void Particles2D::set_fixed_fps(int p_count) {
-	fixed_fps = p_count;
-	VS::get_singleton()->particles_set_fixed_fps(particles, p_count);
-}
-
-int Particles2D::get_fixed_fps() const {
-	return fixed_fps;
-}
-
-void Particles2D::set_fractional_delta(bool p_enable) {
-	fractional_delta = p_enable;
-	VS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
-}
-
-bool Particles2D::get_fractional_delta() const {
-	return fractional_delta;
-}
-
-String Particles2D::get_configuration_warning() const {
-
-	if (VisualServer::get_singleton()->is_low_end()) {
-		return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles\" option for this purpose.");
-	}
-
-	String warnings;
-
-	if (process_material.is_null()) {
-		if (warnings != String())
-			warnings += "\n";
-		warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
-	} else {
-
-		CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
-
-		if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
-			const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
-			if (process &&
-					(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
-							process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
-				if (warnings != String())
-					warnings += "\n";
-				warnings += "- " + TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
-			}
-		}
-	}
-
-	return warnings;
-}
-
-Rect2 Particles2D::capture_rect() const {
-
-	AABB aabb = VS::get_singleton()->particles_get_current_aabb(particles);
-	Rect2 r;
-	r.position.x = aabb.position.x;
-	r.position.y = aabb.position.y;
-	r.size.x = aabb.size.x;
-	r.size.y = aabb.size.y;
-	return r;
-}
-
-void Particles2D::set_texture(const Ref<Texture2D> &p_texture) {
-	texture = p_texture;
-	update();
-}
-
-Ref<Texture2D> Particles2D::get_texture() const {
-	return texture;
-}
-
-void Particles2D::set_normal_map(const Ref<Texture2D> &p_normal_map) {
-
-	normal_map = p_normal_map;
-	update();
-}
-
-Ref<Texture2D> Particles2D::get_normal_map() const {
-	return normal_map;
-}
-
-void Particles2D::_validate_property(PropertyInfo &property) const {
-}
-
-void Particles2D::restart() {
-	VS::get_singleton()->particles_restart(particles);
-	VS::get_singleton()->particles_set_emitting(particles, true);
-}
-
-void Particles2D::_notification(int p_what) {
-
-	if (p_what == NOTIFICATION_DRAW) {
-
-		RID texture_rid;
-		if (texture.is_valid())
-			texture_rid = texture->get_rid();
-		RID normal_rid;
-		if (normal_map.is_valid())
-			normal_rid = normal_map->get_rid();
-
-		VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid);
-
-#ifdef TOOLS_ENABLED
-		if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) {
-
-			draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false);
-		}
-#endif
-	}
-
-	if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
-		if (can_process()) {
-			VS::get_singleton()->particles_set_speed_scale(particles, speed_scale);
-		} else {
-
-			VS::get_singleton()->particles_set_speed_scale(particles, 0);
-		}
-	}
-
-	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
-		_update_particle_emission_transform();
-	}
-
-	if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
-		if (one_shot && !is_emitting()) {
-			_change_notify();
-			set_process_internal(false);
-		}
-	}
-}
-
-void Particles2D::_bind_methods() {
-
-	ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles2D::set_emitting);
-	ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles2D::set_amount);
-	ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles2D::set_lifetime);
-	ClassDB::bind_method(D_METHOD("set_one_shot", "secs"), &Particles2D::set_one_shot);
-	ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time);
-	ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio);
-	ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio);
-	ClassDB::bind_method(D_METHOD("set_visibility_rect", "visibility_rect"), &Particles2D::set_visibility_rect);
-	ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles2D::set_use_local_coordinates);
-	ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles2D::set_fixed_fps);
-	ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles2D::set_fractional_delta);
-	ClassDB::bind_method(D_METHOD("set_process_material", "material"), &Particles2D::set_process_material);
-	ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &Particles2D::set_speed_scale);
-
-	ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting);
-	ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount);
-	ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles2D::get_lifetime);
-	ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles2D::get_one_shot);
-	ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles2D::get_pre_process_time);
-	ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles2D::get_explosiveness_ratio);
-	ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles2D::get_randomness_ratio);
-	ClassDB::bind_method(D_METHOD("get_visibility_rect"), &Particles2D::get_visibility_rect);
-	ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &Particles2D::get_use_local_coordinates);
-	ClassDB::bind_method(D_METHOD("get_fixed_fps"), &Particles2D::get_fixed_fps);
-	ClassDB::bind_method(D_METHOD("get_fractional_delta"), &Particles2D::get_fractional_delta);
-	ClassDB::bind_method(D_METHOD("get_process_material"), &Particles2D::get_process_material);
-	ClassDB::bind_method(D_METHOD("get_speed_scale"), &Particles2D::get_speed_scale);
-
-	ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &Particles2D::set_draw_order);
-	ClassDB::bind_method(D_METHOD("get_draw_order"), &Particles2D::get_draw_order);
-
-	ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Particles2D::set_texture);
-	ClassDB::bind_method(D_METHOD("get_texture"), &Particles2D::get_texture);
-
-	ClassDB::bind_method(D_METHOD("set_normal_map", "texture"), &Particles2D::set_normal_map);
-	ClassDB::bind_method(D_METHOD("get_normal_map"), &Particles2D::get_normal_map);
-
-	ClassDB::bind_method(D_METHOD("capture_rect"), &Particles2D::capture_rect);
-
-	ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
-
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
-	ADD_GROUP("Time", "");
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
-	ADD_GROUP("Drawing", "");
-	ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order");
-	ADD_GROUP("Process Material", "process_");
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
-	ADD_GROUP("Textures", "");
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_map", "get_normal_map");
-
-	BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX);
-	BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
-}
-
-Particles2D::Particles2D() {
-
-	particles = VS::get_singleton()->particles_create();
-
-	one_shot = false; // Needed so that set_emitting doesn't access uninitialized values
-	set_emitting(true);
-	set_one_shot(false);
-	set_amount(8);
-	set_lifetime(1);
-	set_fixed_fps(0);
-	set_fractional_delta(true);
-	set_pre_process_time(0);
-	set_explosiveness_ratio(0);
-	set_randomness_ratio(0);
-	set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
-	set_use_local_coordinates(true);
-	set_draw_order(DRAW_ORDER_INDEX);
-	set_speed_scale(1);
-}
-
-Particles2D::~Particles2D() {
-
-	VS::get_singleton()->free(particles);
-}
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
deleted file mode 100644
index 66281d7950..0000000000
--- a/scene/2d/particles_2d.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*************************************************************************/
-/*  particles_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 PARTICLES_2D_H
-#define PARTICLES_2D_H
-
-#include "core/rid.h"
-#include "scene/2d/node_2d.h"
-#include "scene/resources/texture.h"
-
-class Particles2D : public Node2D {
-private:
-	GDCLASS(Particles2D, Node2D);
-
-public:
-	enum DrawOrder {
-		DRAW_ORDER_INDEX,
-		DRAW_ORDER_LIFETIME,
-	};
-
-private:
-	RID particles;
-
-	bool one_shot;
-	int amount;
-	float lifetime;
-	float pre_process_time;
-	float explosiveness_ratio;
-	float randomness_ratio;
-	float speed_scale;
-	Rect2 visibility_rect;
-	bool local_coords;
-	int fixed_fps;
-	bool fractional_delta;
-
-	Ref<Material> process_material;
-
-	DrawOrder draw_order;
-
-	Ref<Texture2D> texture;
-	Ref<Texture2D> normal_map;
-
-	void _update_particle_emission_transform();
-
-protected:
-	static void _bind_methods();
-	virtual void _validate_property(PropertyInfo &property) const;
-	void _notification(int p_what);
-
-public:
-	void set_emitting(bool p_emitting);
-	void set_amount(int p_amount);
-	void set_lifetime(float p_lifetime);
-	void set_one_shot(bool p_enable);
-	void set_pre_process_time(float p_time);
-	void set_explosiveness_ratio(float p_ratio);
-	void set_randomness_ratio(float p_ratio);
-	void set_visibility_rect(const Rect2 &p_visibility_rect);
-	void set_use_local_coordinates(bool p_enable);
-	void set_process_material(const Ref<Material> &p_material);
-	void set_speed_scale(float p_scale);
-
-	bool is_emitting() const;
-	int get_amount() const;
-	float get_lifetime() const;
-	bool get_one_shot() const;
-	float get_pre_process_time() const;
-	float get_explosiveness_ratio() const;
-	float get_randomness_ratio() const;
-	Rect2 get_visibility_rect() const;
-	bool get_use_local_coordinates() const;
-	Ref<Material> get_process_material() const;
-	float get_speed_scale() const;
-
-	void set_fixed_fps(int p_count);
-	int get_fixed_fps() const;
-
-	void set_fractional_delta(bool p_enable);
-	bool get_fractional_delta() const;
-
-	void set_draw_order(DrawOrder p_order);
-	DrawOrder get_draw_order() const;
-
-	void set_texture(const Ref<Texture2D> &p_texture);
-	Ref<Texture2D> get_texture() const;
-
-	void set_normal_map(const Ref<Texture2D> &p_normal_map);
-	Ref<Texture2D> get_normal_map() const;
-
-	virtual String get_configuration_warning() const;
-
-	void restart();
-	Rect2 capture_rect() const;
-	Particles2D();
-	~Particles2D();
-};
-
-VARIANT_ENUM_CAST(Particles2D::DrawOrder)
-
-#endif // PARTICLES_2D_H
diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp
index 6c1d7c3749..c374dd5faa 100644
--- a/scene/2d/visibility_notifier_2d.cpp
+++ b/scene/2d/visibility_notifier_2d.cpp
@@ -31,7 +31,7 @@
 #include "visibility_notifier_2d.h"
 
 #include "core/engine.h"
-#include "particles_2d.h"
+#include "gpu_particles_2d.h"
 #include "scene/2d/animated_sprite_2d.h"
 #include "scene/2d/physics_body_2d.h"
 #include "scene/animation/animation_player.h"
@@ -212,7 +212,7 @@ void VisibilityEnabler2D::_find_nodes(Node *p_node) {
 	}
 
 	{
-		Particles2D *ps = Object::cast_to<Particles2D>(p_node);
+		GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
 		if (ps) {
 			add = true;
 		}
@@ -304,7 +304,7 @@ void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) {
 	}
 
 	if (enabler[ENABLER_PAUSE_PARTICLES]) {
-		Particles2D *ps = Object::cast_to<Particles2D>(p_node);
+		GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node);
 
 		if (ps) {
 
-- 
cgit v1.2.3