summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/doc_data.h8
-rw-r--r--core/math/a_star_grid_2d.cpp12
-rw-r--r--doc/classes/AnimatedSprite3D.xml6
-rw-r--r--editor/create_dialog.cpp9
-rw-r--r--editor/doc_tools.cpp88
-rw-r--r--editor/editor_help.cpp94
-rw-r--r--editor/editor_help_search.cpp30
-rw-r--r--editor/editor_help_search.h2
-rw-r--r--modules/gdscript/gdscript.cpp6
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp1
-rw-r--r--scene/2d/animated_sprite_2d.cpp58
-rw-r--r--scene/3d/sprite_3d.cpp180
-rw-r--r--scene/3d/sprite_3d.h11
-rw-r--r--scene/main/node.h4
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.cpp6
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.h7
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl21
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp4
21 files changed, 416 insertions, 141 deletions
diff --git a/core/doc_data.h b/core/doc_data.h
index 1d8d2483e0..3b7bf149b4 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -66,6 +66,8 @@ public:
String return_enum;
String qualifiers;
String description;
+ bool is_deprecated = false;
+ bool is_experimental = false;
Vector<ArgumentDoc> arguments;
Vector<int> errors_returned;
bool operator<(const MethodDoc &p_method) const {
@@ -105,6 +107,8 @@ public:
String enumeration;
bool is_bitfield = false;
String description;
+ bool is_deprecated = false;
+ bool is_experimental = false;
bool operator<(const ConstantDoc &p_const) const {
return name < p_const.name;
}
@@ -126,6 +130,8 @@ public:
String default_value;
bool overridden = false;
String overrides;
+ bool is_deprecated = false;
+ bool is_experimental = false;
bool operator<(const PropertyDoc &p_prop) const {
return name < p_prop.name;
}
@@ -167,6 +173,8 @@ public:
Vector<PropertyDoc> properties;
Vector<MethodDoc> annotations;
Vector<ThemeItemDoc> theme_properties;
+ bool is_deprecated = false;
+ bool is_experimental = false;
bool is_script_doc = false;
String script_path;
bool operator<(const ClassDoc &p_class) const {
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
index 23d7e379ee..ad67cfa852 100644
--- a/core/math/a_star_grid_2d.cpp
+++ b/core/math/a_star_grid_2d.cpp
@@ -30,16 +30,16 @@
#include "a_star_grid_2d.h"
-static real_t heuristic_manhattan(const Vector2i &p_from, const Vector2i &p_to) {
+static real_t heuristic_euclidian(const Vector2i &p_from, const Vector2i &p_to) {
real_t dx = (real_t)ABS(p_to.x - p_from.x);
real_t dy = (real_t)ABS(p_to.y - p_from.y);
- return dx + dy;
+ return (real_t)Math::sqrt(dx * dx + dy * dy);
}
-static real_t heuristic_euclidian(const Vector2i &p_from, const Vector2i &p_to) {
+static real_t heuristic_manhattan(const Vector2i &p_from, const Vector2i &p_to) {
real_t dx = (real_t)ABS(p_to.x - p_from.x);
real_t dy = (real_t)ABS(p_to.y - p_from.y);
- return (real_t)Math::sqrt(dx * dx + dy * dy);
+ return dx + dy;
}
static real_t heuristic_octile(const Vector2i &p_from, const Vector2i &p_to) {
@@ -55,7 +55,7 @@ static real_t heuristic_chebyshev(const Vector2i &p_from, const Vector2i &p_to)
return MAX(dx, dy);
}
-static real_t (*heuristics[AStarGrid2D::HEURISTIC_MAX])(const Vector2i &, const Vector2i &) = { heuristic_manhattan, heuristic_euclidian, heuristic_octile, heuristic_chebyshev };
+static real_t (*heuristics[AStarGrid2D::HEURISTIC_MAX])(const Vector2i &, const Vector2i &) = { heuristic_euclidian, heuristic_manhattan, heuristic_octile, heuristic_chebyshev };
void AStarGrid2D::set_size(const Size2i &p_size) {
ERR_FAIL_COND(p_size.x < 0 || p_size.y < 0);
@@ -572,7 +572,7 @@ void AStarGrid2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "jumping_enabled"), "set_jumping_enabled", "is_jumping_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "default_heuristic", PROPERTY_HINT_ENUM, "Manhattan,Euclidean,Octile,Chebyshev,Max"), "set_default_heuristic", "get_default_heuristic");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "default_heuristic", PROPERTY_HINT_ENUM, "Euclidean,Manhattan,Octile,Chebyshev,Max"), "set_default_heuristic", "get_default_heuristic");
ADD_PROPERTY(PropertyInfo(Variant::INT, "diagonal_mode", PROPERTY_HINT_ENUM, "Never,Always,At Least One Walkable,Only If No Obstacles,Max"), "set_diagonal_mode", "get_diagonal_mode");
BIND_ENUM_CONSTANT(HEURISTIC_EUCLIDEAN);
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index 0bc5484e3a..58d3ca6ad3 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -13,8 +13,9 @@
<method name="play">
<return type="void" />
<param index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
+ <param index="1" name="backwards" type="bool" default="false" />
<description>
- Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played.
+ Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation will be played in reverse.
</description>
</method>
<method name="stop">
@@ -37,6 +38,9 @@
<member name="playing" type="bool" setter="set_playing" getter="is_playing" default="false">
If [code]true[/code], the [member animation] is currently playing.
</member>
+ <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
+ The animation speed is multiplied by this value.
+ </member>
</members>
<signals>
<signal name="animation_finished">
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 4ac32d7317..3e72c6211d 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -296,6 +296,15 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String
r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback));
}
+ bool is_deprecated = EditorHelp::get_doc_data()->class_list[p_type].is_deprecated;
+ bool is_experimental = EditorHelp::get_doc_data()->class_list[p_type].is_experimental;
+
+ if (is_deprecated) {
+ r_item->add_button(0, get_theme_icon("StatusError", SNAME("EditorIcons")), 0, false, TTR("This class is marked as deprecated."));
+ } else if (is_experimental) {
+ r_item->add_button(0, get_theme_icon("NodeWarning", SNAME("EditorIcons")), 0, false, TTR("This class is marked as experimental."));
+ }
+
if (!search_box->get_text().is_empty()) {
r_item->set_collapsed(false);
} else {
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index ec9a744e57..9f655ab00a 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -85,6 +85,9 @@ void DocTools::merge_from(const DocTools &p_data) {
const DocData::ClassDoc &cf = p_data.class_list[c.name];
+ c.is_deprecated = cf.is_deprecated;
+ c.is_experimental = cf.is_experimental;
+
c.description = cf.description;
c.brief_description = cf.brief_description;
c.tutorials = cf.tutorials;
@@ -133,6 +136,8 @@ void DocTools::merge_from(const DocTools &p_data) {
const DocData::MethodDoc &mf = cf.constructors[j];
m.description = mf.description;
+ m.is_deprecated = mf.is_deprecated;
+ m.is_experimental = mf.is_experimental;
break;
}
}
@@ -148,6 +153,8 @@ void DocTools::merge_from(const DocTools &p_data) {
const DocData::MethodDoc &mf = cf.methods[j];
m.description = mf.description;
+ m.is_deprecated = mf.is_deprecated;
+ m.is_experimental = mf.is_experimental;
break;
}
}
@@ -162,6 +169,8 @@ void DocTools::merge_from(const DocTools &p_data) {
const DocData::MethodDoc &mf = cf.signals[j];
m.description = mf.description;
+ m.is_deprecated = mf.is_deprecated;
+ m.is_experimental = mf.is_experimental;
break;
}
}
@@ -176,6 +185,8 @@ void DocTools::merge_from(const DocTools &p_data) {
const DocData::ConstantDoc &mf = cf.constants[j];
m.description = mf.description;
+ m.is_deprecated = mf.is_deprecated;
+ m.is_experimental = mf.is_experimental;
break;
}
}
@@ -190,6 +201,8 @@ void DocTools::merge_from(const DocTools &p_data) {
const DocData::MethodDoc &mf = cf.annotations[j];
m.description = mf.description;
+ m.is_deprecated = mf.is_deprecated;
+ m.is_experimental = mf.is_experimental;
break;
}
}
@@ -204,6 +217,8 @@ void DocTools::merge_from(const DocTools &p_data) {
const DocData::PropertyDoc &pf = cf.properties[j];
p.description = pf.description;
+ p.is_deprecated = pf.is_deprecated;
+ p.is_experimental = pf.is_experimental;
break;
}
}
@@ -266,6 +281,8 @@ void DocTools::merge_from(const DocTools &p_data) {
const DocData::MethodDoc &mf = cf.operators[j];
m.description = mf.description;
+ m.is_deprecated = mf.is_deprecated;
+ m.is_experimental = mf.is_experimental;
break;
}
}
@@ -1007,6 +1024,12 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
if (parser->has_attribute("qualifiers")) {
method.qualifiers = parser->get_attribute_value("qualifiers");
}
+ if (parser->has_attribute("is_deprecated")) {
+ method.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ }
+ if (parser->has_attribute("is_experimental")) {
+ method.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ }
while (parser->read() == OK) {
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
@@ -1138,6 +1161,16 @@ Error DocTools::_load(Ref<XMLParser> parser) {
c.inherits = parser->get_attribute_value("inherits");
}
+ if (parser->has_attribute("is_deprecated")) {
+ String result = parser->get_attribute_value("is_deprecated");
+ c.is_deprecated = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ }
+
+ if (parser->has_attribute("is_experimental")) {
+ String result = parser->get_attribute_value("is_experimental");
+ c.is_experimental = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ }
+
while (parser->read() == OK) {
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
String name2 = parser->get_node_name();
@@ -1211,6 +1244,12 @@ Error DocTools::_load(Ref<XMLParser> parser) {
if (parser->has_attribute("enum")) {
prop2.enumeration = parser->get_attribute_value("enum");
}
+ if (parser->has_attribute("is_deprecated")) {
+ prop2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ }
+ if (parser->has_attribute("is_experimental")) {
+ prop2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ }
if (!parser->is_empty()) {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@@ -1275,6 +1314,14 @@ Error DocTools::_load(Ref<XMLParser> parser) {
if (parser->has_attribute("is_bitfield")) {
constant2.is_bitfield = parser->get_attribute_value("is_bitfield").to_lower() == "true";
}
+ if (parser->has_attribute("is_deprecated")) {
+ String result = parser->get_attribute_value("is_deprecated");
+ constant2.is_deprecated = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ }
+ if (parser->has_attribute("is_experimental")) {
+ String result = parser->get_attribute_value("is_experimental");
+ constant2.is_experimental = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ }
if (!parser->is_empty()) {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@@ -1327,7 +1374,15 @@ static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<Do
qualifiers += " qualifiers=\"" + m.qualifiers.xml_escape() + "\"";
}
- _write_string(f, 2, "<" + p_name + " name=\"" + m.name.xml_escape() + "\"" + qualifiers + ">");
+ String additional_attributes;
+ if (m.is_deprecated) {
+ additional_attributes += " is_deprecated=\"True\"";
+ }
+ if (m.is_experimental) {
+ additional_attributes += " is_experimental=\"True\"";
+ }
+
+ _write_string(f, 2, "<" + p_name + " name=\"" + m.name.xml_escape() + "\"" + qualifiers + additional_attributes + ">");
if (!m.return_type.is_empty()) {
String enum_text;
@@ -1390,6 +1445,12 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
String header = "<class name=\"" + c.name + "\"";
if (!c.inherits.is_empty()) {
header += " inherits=\"" + c.inherits + "\"";
+ if (c.is_deprecated) {
+ header += " is_deprecated=\"True\"";
+ }
+ if (c.is_experimental) {
+ header += " is_experimental=\"True\"";
+ }
}
header += String(" version=\"") + VERSION_BRANCH + "\"";
// Reference the XML schema so editors can provide error checking.
@@ -1433,6 +1494,12 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
if (!c.properties[i].default_value.is_empty()) {
additional_attributes += " default=\"" + c.properties[i].default_value.xml_escape(true) + "\"";
}
+ if (c.properties[i].is_deprecated) {
+ additional_attributes += " is_deprecated=\"True\"";
+ }
+ if (c.properties[i].is_experimental) {
+ additional_attributes += " is_experimental=\"True\"";
+ }
const DocData::PropertyDoc &p = c.properties[i];
@@ -1453,21 +1520,30 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
_write_string(f, 1, "<constants>");
for (int i = 0; i < c.constants.size(); i++) {
const DocData::ConstantDoc &k = c.constants[i];
+
+ String additional_attributes;
+ if (c.constants[i].is_deprecated) {
+ additional_attributes += " is_deprecated=\"True\"";
+ }
+ if (c.constants[i].is_experimental) {
+ additional_attributes += " is_experimental=\"True\"";
+ }
+
if (k.is_value_valid) {
if (!k.enumeration.is_empty()) {
if (k.is_bitfield) {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\" is_bitfield=\"true\">");
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\" is_bitfield=\"true\"" + additional_attributes + ">");
} else {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">");
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\"" + additional_attributes + ">");
}
} else {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">");
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\"" + additional_attributes + ">");
}
} else {
if (!k.enumeration.is_empty()) {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\" enum=\"" + k.enumeration + "\">");
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\" enum=\"" + k.enumeration + "\"" + additional_attributes + ">");
} else {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\">");
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\"" + additional_attributes + ">");
}
}
_write_string(f, 3, _translate_doc_string(k.description).strip_edges().xml_escape());
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index b8f115e82e..745dcdd04c 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -276,6 +276,23 @@ String EditorHelp::_fix_constant(const String &p_constant) const {
return p_constant;
}
+// Macros for assigning the deprecation/experimental information to class members
+#define DEPRECATED_DOC_TAG \
+ class_desc->push_color(get_theme_color(SNAME("error_color"), SNAME("Editor"))); \
+ Ref<Texture2D> error_icon = get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")); \
+ class_desc->add_text(" "); \
+ class_desc->add_image(error_icon, error_icon->get_width(), error_icon->get_height()); \
+ class_desc->add_text(" (" + TTR("Deprecated") + ")"); \
+ class_desc->pop();
+
+#define EXPERIMENTAL_DOC_TAG \
+ class_desc->push_color(get_theme_color(SNAME("warning_color"), SNAME("Editor"))); \
+ Ref<Texture2D> warning_icon = get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")); \
+ class_desc->add_text(" "); \
+ class_desc->add_image(warning_icon, warning_icon->get_width(), warning_icon->get_height()); \
+ class_desc->add_text(" (" + TTR("Experimental") + ")"); \
+ class_desc->pop();
+
void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview) {
method_line[p_method.name] = class_desc->get_paragraph_count() - 2; //gets overridden if description
@@ -356,6 +373,14 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
class_desc->pop();
}
+ if (p_method.is_deprecated) {
+ DEPRECATED_DOC_TAG;
+ }
+
+ if (p_method.is_experimental) {
+ EXPERIMENTAL_DOC_TAG;
+ }
+
if (p_overview) {
class_desc->pop(); //cell
}
@@ -565,6 +590,17 @@ void EditorHelp::_update_doc() {
class_desc->pop(); // color
class_desc->pop(); // font size
class_desc->pop(); // font
+
+ if (cd.is_deprecated) {
+ class_desc->add_text(" ");
+ Ref<Texture2D> error_icon = get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons"));
+ class_desc->add_image(error_icon, error_icon->get_width(), error_icon->get_height());
+ }
+ if (cd.is_experimental) {
+ class_desc->add_text(" ");
+ Ref<Texture2D> warning_icon = get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons"));
+ class_desc->add_image(warning_icon, warning_icon->get_width(), warning_icon->get_height());
+ }
class_desc->add_newline();
const String non_breaking_space = String::chr(160);
@@ -627,6 +663,26 @@ void EditorHelp::_update_doc() {
}
}
+ // Note if deprecated.
+ if (cd.is_deprecated) {
+ Ref<Texture2D> error_icon = get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons"));
+ class_desc->push_color(get_theme_color(SNAME("error_color"), SNAME("Editor")));
+ class_desc->add_image(error_icon, error_icon->get_width(), error_icon->get_height());
+ class_desc->add_text(String(" ") + TTR("This class is marked as deprecated. It will be removed in future versions."));
+ class_desc->pop();
+ class_desc->add_newline();
+ }
+
+ // Note if experimental.
+ if (cd.is_experimental) {
+ Ref<Texture2D> warning_icon = get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons"));
+ class_desc->push_color(get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ class_desc->add_image(warning_icon, warning_icon->get_width(), warning_icon->get_height());
+ class_desc->add_text(String(" ") + TTR("This class is marked as experimental. It is subject to likely change or possible removal in future versions. Use at your own discretion."));
+ class_desc->pop();
+ class_desc->add_newline();
+ }
+
class_desc->add_newline();
class_desc->add_newline();
@@ -817,6 +873,13 @@ void EditorHelp::_update_doc() {
class_desc->pop();
}
+ if (cd.properties[i].is_deprecated) {
+ DEPRECATED_DOC_TAG;
+ }
+ if (cd.properties[i].is_experimental) {
+ EXPERIMENTAL_DOC_TAG;
+ }
+
class_desc->pop();
class_desc->pop(); // cell
@@ -1066,6 +1129,14 @@ void EditorHelp::_update_doc() {
class_desc->push_color(symbol_color);
class_desc->add_text(")");
+
+ if (cd.signals[i].is_deprecated) {
+ DEPRECATED_DOC_TAG;
+ }
+ if (cd.signals[i].is_experimental) {
+ EXPERIMENTAL_DOC_TAG;
+ }
+
class_desc->pop();
class_desc->pop(); // end monofont
if (!cd.signals[i].description.strip_edges().is_empty()) {
@@ -1187,6 +1258,14 @@ void EditorHelp::_update_doc() {
class_desc->pop();
class_desc->pop();
+ if (enum_list[i].is_deprecated) {
+ DEPRECATED_DOC_TAG;
+ }
+
+ if (enum_list[i].is_experimental) {
+ EXPERIMENTAL_DOC_TAG;
+ }
+
class_desc->add_newline();
if (!enum_list[i].description.strip_edges().is_empty()) {
@@ -1258,6 +1337,14 @@ void EditorHelp::_update_doc() {
class_desc->pop();
+ if (constants[i].is_deprecated) {
+ DEPRECATED_DOC_TAG;
+ }
+
+ if (constants[i].is_experimental) {
+ EXPERIMENTAL_DOC_TAG;
+ }
+
class_desc->add_newline();
if (!constants[i].description.strip_edges().is_empty()) {
@@ -1438,6 +1525,13 @@ void EditorHelp::_update_doc() {
class_desc->pop(); // color
}
+ if (cd.properties[i].is_deprecated) {
+ DEPRECATED_DOC_TAG;
+ }
+ if (cd.properties[i].is_experimental) {
+ EXPERIMENTAL_DOC_TAG;
+ }
+
if (cd.is_script_doc && (!cd.properties[i].setter.is_empty() || !cd.properties[i].getter.is_empty())) {
class_desc->push_color(symbol_color);
class_desc->add_text(" [" + TTR("property:") + " ");
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index af0cff9ad6..129ad4d33b 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -599,6 +599,14 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const
item->set_custom_color(1, disabled_color);
}
+ if (p_doc->is_deprecated) {
+ Ref<Texture2D> error_icon = ui_service->get_theme_icon("StatusError", SNAME("EditorIcons"));
+ item->add_button(0, error_icon, 0, false, TTR("This class is marked as deprecated."));
+ } else if (p_doc->is_experimental) {
+ Ref<Texture2D> warning_icon = ui_service->get_theme_icon("NodeWarning", SNAME("EditorIcons"));
+ item->add_button(0, warning_icon, 0, false, TTR("This class is marked as experimental."));
+ }
+
_match_item(item, p_doc->name);
return item;
@@ -606,37 +614,37 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const
TreeItem *EditorHelpSearch::Runner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) {
String tooltip = _build_method_tooltip(p_class_doc, p_doc);
- return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) {
String tooltip = _build_method_tooltip(p_class_doc, p_doc);
- return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_annotation_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) {
String tooltip = _build_method_tooltip(p_class_doc, p_doc);
- return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_doc->name, p_text, TTRC("Annotation"), "annotation", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberAnnotation", p_doc->name, p_text, TTRC("Annotation"), "annotation", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) {
String tooltip = p_class_doc->name + "." + p_doc->name;
- return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) {
String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name;
tooltip += "\n " + p_class_doc->name + "." + p_doc->setter + "(value) setter";
tooltip += "\n " + p_class_doc->name + "." + p_doc->getter + "() getter";
- return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, p_doc->name, TTRC("Property"), "property", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, p_doc->name, TTRC("Property"), "property", tooltip, p_doc->is_deprecated, p_doc->is_experimental);
}
TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc) {
String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name;
- return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, p_doc->name, TTRC("Theme Property"), "theme_item", tooltip);
+ return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, p_doc->name, TTRC("Theme Property"), "theme_item", tooltip, false, false);
}
-TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip) {
+TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, bool is_deprecated, bool is_experimental) {
Ref<Texture2D> icon;
String text;
if (search_flags & SEARCH_SHOW_HIERARCHY) {
@@ -655,6 +663,14 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons
item->set_tooltip_text(1, p_tooltip);
item->set_metadata(0, "class_" + p_metatype + ":" + p_class_name + ":" + p_name);
+ if (is_deprecated) {
+ Ref<Texture2D> error_icon = ui_service->get_theme_icon("StatusError", SNAME("EditorIcons"));
+ item->add_button(0, error_icon, 0, false, TTR("This member is marked as deprecated."));
+ } else if (is_experimental) {
+ Ref<Texture2D> warning_icon = ui_service->get_theme_icon("NodeWarning", SNAME("EditorIcons"));
+ item->add_button(0, warning_icon, 0, false, TTR("This member is marked as experimental."));
+ }
+
_match_item(item, p_name);
return item;
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index 26abaec6e6..efd8645cd7 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -155,7 +155,7 @@ class EditorHelpSearch::Runner : public RefCounted {
TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc);
TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc);
TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc);
- TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip);
+ TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, bool is_deprecated, bool is_experimental);
public:
bool work(uint64_t slot = 100000);
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 10babad378..1cff2181af 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1077,10 +1077,12 @@ Error GDScript::load_source_code(const String &p_path) {
}
source = s;
+ path = p_path;
#ifdef TOOLS_ENABLED
source_changed_cache = true;
-#endif
- path = p_path;
+ set_edited(false);
+ set_last_modified_time(FileAccess::get_modified_time(path));
+#endif // TOOLS_ENABLED
return OK;
}
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index 6f60318b3b..9d0864e4d5 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -101,6 +101,7 @@ int MultiplayerSpawner::get_spawnable_scene_count() const {
return spawnable_scenes.size();
}
String MultiplayerSpawner::get_spawnable_scene(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, (int)spawnable_scenes.size(), "");
return spawnable_scenes[p_idx].path;
}
void MultiplayerSpawner::clear_spawnable_scenes() {
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index b1b1cb23ed..09255ba834 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -175,33 +175,38 @@ void AnimatedSprite2D::_notification(int p_what) {
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) {
+ int last_frame = frames->get_frame_count(animation) - 1;
+ if (!backwards) {
+ // Forward.
+ if (frame >= last_frame) {
+ if (frames->get_animation_loop(animation)) {
frame = 0;
- } else {
- frame = fc - 1;
- }
-
- if (!is_over) {
- is_over = true;
emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = last_frame;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
}
+ } else {
+ frame++;
}
} else {
- if (backwards) {
- frame--;
+ // Reversed.
+ if (frame <= 0) {
+ if (frames->get_animation_loop(animation)) {
+ frame = last_frame;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = 0;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
+ }
} else {
- frame++;
+ frame--;
}
}
@@ -259,14 +264,15 @@ void AnimatedSprite2D::_notification(int p_what) {
void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
if (frames.is_valid()) {
- frames->disconnect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed));
+ frames->disconnect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite2D::_res_changed));
}
+
frames = p_frames;
if (frames.is_valid()) {
- frames->connect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed));
+ frames->connect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite2D::_res_changed));
}
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
frame = 0;
} else {
set_frame(frame);
@@ -283,7 +289,7 @@ Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const {
}
void AnimatedSprite2D::set_frame(int p_frame) {
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
return;
}
@@ -318,7 +324,7 @@ void AnimatedSprite2D::set_speed_scale(double p_speed_scale) {
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
+ // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
_reset_timeout();
timeout -= elapsed;
}
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 4515277dc3..a4a6c211d7 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -30,7 +30,6 @@
#include "sprite_3d.h"
-#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
Color SpriteBase3D::_get_color_accum() {
@@ -58,7 +57,7 @@ void SpriteBase3D::_propagate_color_changed() {
}
color_dirty = true;
- _queue_update();
+ _queue_redraw();
for (SpriteBase3D *&E : children) {
E->_propagate_color_changed();
@@ -90,7 +89,7 @@ void SpriteBase3D::_notification(int p_what) {
void SpriteBase3D::set_centered(bool p_center) {
centered = p_center;
- _queue_update();
+ _queue_redraw();
}
bool SpriteBase3D::is_centered() const {
@@ -99,7 +98,7 @@ bool SpriteBase3D::is_centered() const {
void SpriteBase3D::set_offset(const Point2 &p_offset) {
offset = p_offset;
- _queue_update();
+ _queue_redraw();
}
Point2 SpriteBase3D::get_offset() const {
@@ -108,7 +107,7 @@ Point2 SpriteBase3D::get_offset() const {
void SpriteBase3D::set_flip_h(bool p_flip) {
hflip = p_flip;
- _queue_update();
+ _queue_redraw();
}
bool SpriteBase3D::is_flipped_h() const {
@@ -117,7 +116,7 @@ bool SpriteBase3D::is_flipped_h() const {
void SpriteBase3D::set_flip_v(bool p_flip) {
vflip = p_flip;
- _queue_update();
+ _queue_redraw();
}
bool SpriteBase3D::is_flipped_v() const {
@@ -127,7 +126,7 @@ bool SpriteBase3D::is_flipped_v() const {
void SpriteBase3D::set_modulate(const Color &p_color) {
modulate = p_color;
_propagate_color_changed();
- _queue_update();
+ _queue_redraw();
}
Color SpriteBase3D::get_modulate() const {
@@ -137,7 +136,7 @@ Color SpriteBase3D::get_modulate() const {
void SpriteBase3D::set_render_priority(int p_priority) {
ERR_FAIL_COND(p_priority < RS::MATERIAL_RENDER_PRIORITY_MIN || p_priority > RS::MATERIAL_RENDER_PRIORITY_MAX);
render_priority = p_priority;
- _queue_update();
+ _queue_redraw();
}
int SpriteBase3D::get_render_priority() const {
@@ -146,7 +145,7 @@ int SpriteBase3D::get_render_priority() const {
void SpriteBase3D::set_pixel_size(real_t p_amount) {
pixel_size = p_amount;
- _queue_update();
+ _queue_redraw();
}
real_t SpriteBase3D::get_pixel_size() const {
@@ -156,7 +155,7 @@ real_t SpriteBase3D::get_pixel_size() const {
void SpriteBase3D::set_axis(Vector3::Axis p_axis) {
ERR_FAIL_INDEX(p_axis, 3);
axis = p_axis;
- _queue_update();
+ _queue_redraw();
}
Vector3::Axis SpriteBase3D::get_axis() const {
@@ -171,7 +170,8 @@ void SpriteBase3D::_im_update() {
//texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
}
-void SpriteBase3D::_queue_update() {
+void SpriteBase3D::_queue_redraw() {
+ // The 3D equivalent of CanvasItem.queue_redraw().
if (pending_update) {
return;
}
@@ -250,7 +250,7 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags[p_flag] = p_enable;
- _queue_update();
+ _queue_redraw();
}
bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const {
@@ -261,7 +261,7 @@ bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const {
void SpriteBase3D::set_alpha_cut_mode(AlphaCutMode p_mode) {
ERR_FAIL_INDEX(p_mode, 3);
alpha_cut = p_mode;
- _queue_update();
+ _queue_redraw();
}
SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const {
@@ -269,9 +269,9 @@ SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const {
}
void SpriteBase3D::set_billboard_mode(StandardMaterial3D::BillboardMode p_mode) {
- ERR_FAIL_INDEX(p_mode, 3);
+ ERR_FAIL_INDEX(p_mode, 3); // Cannot use BILLBOARD_PARTICLES.
billboard_mode = p_mode;
- _queue_update();
+ _queue_redraw();
}
StandardMaterial3D::BillboardMode SpriteBase3D::get_billboard_mode() const {
@@ -281,7 +281,7 @@ StandardMaterial3D::BillboardMode SpriteBase3D::get_billboard_mode() const {
void SpriteBase3D::set_texture_filter(StandardMaterial3D::TextureFilter p_filter) {
if (texture_filter != p_filter) {
texture_filter = p_filter;
- _queue_update();
+ _queue_redraw();
}
}
@@ -329,7 +329,6 @@ void SpriteBase3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh);
- ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update);
ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
@@ -368,7 +367,7 @@ SpriteBase3D::SpriteBase3D() {
}
material = RenderingServer::get_singleton()->material_create();
- // Set defaults for material, names need to match up those in StandardMaterial3D
+ // Set defaults for material, names need to match up those in StandardMaterial3D.
RS::get_singleton()->material_set_param(material, "albedo", Color(1, 1, 1, 1));
RS::get_singleton()->material_set_param(material, "specular", 0.5);
RS::get_singleton()->material_set_param(material, "metallic", 0.0);
@@ -394,7 +393,7 @@ SpriteBase3D::SpriteBase3D() {
mesh_colors.resize(4);
mesh_uvs.resize(4);
- // create basic mesh and store format information
+ // Create basic mesh and store format information.
for (int i = 0; i < 4; i++) {
mesh_normals.write[i] = Vector3(0.0, 0.0, 0.0);
mesh_tangents.write[i * 4 + 0] = 0.0;
@@ -554,7 +553,7 @@ void Sprite3D::_draw() {
AABB aabb;
- // Everything except position and UV is compressed
+ // Everything except position and UV is compressed.
uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
@@ -637,13 +636,14 @@ void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) {
return;
}
if (texture.is_valid()) {
- texture->disconnect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update"));
+ texture->disconnect(SceneStringNames::get_singleton()->changed, callable_mp((SpriteBase3D *)this, &Sprite3D::_queue_redraw));
}
texture = p_texture;
if (texture.is_valid()) {
- texture->connect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update"));
+ texture->connect(SceneStringNames::get_singleton()->changed, callable_mp((SpriteBase3D *)this, &Sprite3D::_queue_redraw));
}
- _queue_update();
+
+ _queue_redraw();
emit_signal(SceneStringNames::get_singleton()->texture_changed);
}
@@ -657,7 +657,7 @@ void Sprite3D::set_region_enabled(bool p_region) {
}
region = p_region;
- _queue_update();
+ _queue_redraw();
}
bool Sprite3D::is_region_enabled() const {
@@ -668,7 +668,7 @@ void Sprite3D::set_region_rect(const Rect2 &p_region_rect) {
bool changed = region_rect != p_region_rect;
region_rect = p_region_rect;
if (region && changed) {
- _queue_update();
+ _queue_redraw();
}
}
@@ -681,7 +681,7 @@ void Sprite3D::set_frame(int p_frame) {
frame = p_frame;
- _queue_update();
+ _queue_redraw();
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -704,7 +704,7 @@ Vector2i Sprite3D::get_frame_coords() const {
void Sprite3D::set_vframes(int p_amount) {
ERR_FAIL_COND(p_amount < 1);
vframes = p_amount;
- _queue_update();
+ _queue_redraw();
notify_property_list_changed();
}
@@ -715,7 +715,7 @@ int Sprite3D::get_vframes() const {
void Sprite3D::set_hframes(int p_amount) {
ERR_FAIL_COND(p_amount < 1);
hframes = p_amount;
- _queue_update();
+ _queue_redraw();
notify_property_list_changed();
}
@@ -820,9 +820,9 @@ void AnimatedSprite3D::_draw() {
}
Ref<Texture2D> texture = frames->get_frame(animation, frame);
- if (!texture.is_valid()) {
+ if (texture.is_null()) {
set_base(RID());
- return; //no texuture no life
+ return;
}
Size2 tsize = texture->get_size();
if (tsize.x == 0 || tsize.y == 0) {
@@ -917,7 +917,7 @@ void AnimatedSprite3D::_draw() {
AABB aabb;
- // Everything except position and UV is compressed
+ // Everything except position and UV is compressed.
uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
uint8_t *attribute_write_buffer = attribute_buffer.ptrw();
@@ -1056,27 +1056,51 @@ void AnimatedSprite3D::_notification(int p_what) {
double remaining = get_process_delta_time();
while (remaining) {
- double speed = frames->get_animation_speed(animation);
+ double speed = frames->get_animation_speed(animation) * speed_scale;
if (speed == 0) {
return; // Do nothing.
}
if (timeout <= 0) {
- timeout = 1.0 / speed;
-
- int fc = frames->get_frame_count(animation);
- if (frame >= fc - 1) {
- if (frames->get_animation_loop(animation)) {
- frame = 0;
+ timeout = _get_frame_duration();
+
+ int last_frame = frames->get_frame_count(animation) - 1;
+ if (!backwards) {
+ // Forward.
+ if (frame >= last_frame) {
+ if (frames->get_animation_loop(animation)) {
+ frame = 0;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = last_frame;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
+ }
} else {
- frame = fc - 1;
+ frame++;
}
- emit_signal(SceneStringNames::get_singleton()->animation_finished);
} else {
- frame++;
+ // Reversed.
+ if (frame <= 0) {
+ if (frames->get_animation_loop(animation)) {
+ frame = last_frame;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = 0;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
+ }
+ } else {
+ frame--;
+ }
}
- _queue_update();
+ _queue_redraw();
+
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -1090,14 +1114,15 @@ void AnimatedSprite3D::_notification(int p_what) {
void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
if (frames.is_valid()) {
- frames->disconnect("changed", Callable(this, "_res_changed"));
+ frames->disconnect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite3D::_res_changed));
}
+
frames = p_frames;
if (frames.is_valid()) {
- frames->connect("changed", Callable(this, "_res_changed"));
+ frames->connect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite3D::_res_changed));
}
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
frame = 0;
} else {
set_frame(frame);
@@ -1105,7 +1130,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
notify_property_list_changed();
_reset_timeout();
- _queue_update();
+ _queue_redraw();
update_configuration_warnings();
}
@@ -1114,7 +1139,7 @@ Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const {
}
void AnimatedSprite3D::set_frame(int p_frame) {
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
return;
}
@@ -1135,7 +1160,8 @@ void AnimatedSprite3D::set_frame(int p_frame) {
frame = p_frame;
_reset_timeout();
- _queue_update();
+ _queue_redraw();
+
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -1143,6 +1169,20 @@ int AnimatedSprite3D::get_frame() const {
return frame;
}
+void AnimatedSprite3D::set_speed_scale(double p_speed_scale) {
+ double 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;
+}
+
+double AnimatedSprite3D::get_speed_scale() const {
+ return speed_scale;
+}
+
Rect2 AnimatedSprite3D::get_item_rect() const {
if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
return Rect2(0, 0, 1, 1);
@@ -1171,7 +1211,8 @@ Rect2 AnimatedSprite3D::get_item_rect() const {
void AnimatedSprite3D::_res_changed() {
set_frame(frame);
- _queue_update();
+
+ _queue_redraw();
}
void AnimatedSprite3D::set_playing(bool p_playing) {
@@ -1187,10 +1228,17 @@ bool AnimatedSprite3D::is_playing() const {
return playing;
}
-void AnimatedSprite3D::play(const StringName &p_animation) {
+void AnimatedSprite3D::play(const StringName &p_animation, const bool p_backwards) {
+ backwards = p_backwards;
+
if (p_animation) {
set_animation(p_animation);
+ if (frames.is_valid() && backwards && get_frame() == 0) {
+ set_frame(frames->get_frame_count(p_animation) - 1);
+ }
}
+
+ is_over = false;
set_playing(true);
}
@@ -1198,24 +1246,28 @@ void AnimatedSprite3D::stop() {
set_playing(false);
}
+double AnimatedSprite3D::_get_frame_duration() {
+ if (frames.is_valid() && frames->has_animation(animation)) {
+ double speed = frames->get_animation_speed(animation) * speed_scale;
+ if (speed > 0) {
+ return 1.0 / speed;
+ }
+ }
+ return 0.0;
+}
+
void AnimatedSprite3D::_reset_timeout() {
if (!playing) {
return;
}
- if (frames.is_valid() && frames->has_animation(animation)) {
- float speed = frames->get_animation_speed(animation);
- if (speed > 0) {
- timeout = 1.0 / speed;
- } else {
- timeout = 0;
- }
- } else {
- timeout = 0;
- }
+ timeout = _get_frame_duration();
+ is_over = false;
}
void AnimatedSprite3D::set_animation(const StringName &p_animation) {
+ ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", p_animation));
+ ERR_FAIL_COND_MSG(!frames->get_animation_names().has(p_animation), vformat("There is no animation with name '%s'.", p_animation));
if (animation == p_animation) {
return;
}
@@ -1224,7 +1276,7 @@ void AnimatedSprite3D::set_animation(const StringName &p_animation) {
_reset_timeout();
set_frame(0);
notify_property_list_changed();
- _queue_update();
+ _queue_redraw();
}
StringName AnimatedSprite3D::get_animation() const {
@@ -1261,12 +1313,15 @@ void AnimatedSprite3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_playing", "playing"), &AnimatedSprite3D::set_playing);
ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite3D::is_playing);
- ClassDB::bind_method(D_METHOD("play", "anim"), &AnimatedSprite3D::play, DEFVAL(StringName()));
+ ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite3D::play, DEFVAL(StringName()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite3D::stop);
ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame);
ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite3D::set_speed_scale);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite3D::get_speed_scale);
+
ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite3D::_res_changed);
ADD_SIGNAL(MethodInfo("frame_changed"));
@@ -1275,6 +1330,7 @@ void AnimatedSprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "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");
}
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 84244a2476..e6a546a76d 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -106,7 +106,7 @@ protected:
uint32_t skin_stride = 0;
uint32_t mesh_surface_format = 0;
- void _queue_update();
+ void _queue_redraw();
public:
void set_centered(bool p_center);
@@ -209,15 +209,19 @@ class AnimatedSprite3D : public SpriteBase3D {
Ref<SpriteFrames> frames;
bool playing = false;
+ bool backwards = false;
StringName animation = "default";
int frame = 0;
+ float speed_scale = 1.0f;
bool centered = false;
+ bool is_over = false;
double timeout = 0.0;
void _res_changed();
+ double _get_frame_duration();
void _reset_timeout();
RID last_shader;
@@ -233,7 +237,7 @@ public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
- void play(const StringName &p_animation = StringName());
+ void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
void stop();
void set_playing(bool p_playing);
@@ -245,6 +249,9 @@ public:
void set_frame(int p_frame);
int get_frame() const;
+ void set_speed_scale(double p_speed_scale);
+ double get_speed_scale() const;
+
virtual Rect2 get_item_rect() const override;
virtual TypedArray<String> get_configuration_warnings() const override;
diff --git a/scene/main/node.h b/scene/main/node.h
index 39225b1358..13a938ef97 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -529,4 +529,8 @@ Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args)
return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
+// Add these macro to your class's 'get_configuration_warnings' function to have warnings show up in the scene tree inspector.
+#define DEPRECATED_NODE_WARNING warnings.push_back(RTR("This node is marked as deprecated and will be removed in future versions.\nPlease check the Godot documentation for information about migration."));
+#define EXPERIMENTAL_NODE_WARNING warnings.push_back(RTR("This node is marked as experimental and may be subject to removal or major changes in future versions."));
+
#endif // NODE_H
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp
index 315bea2e67..971e9243e3 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp
@@ -1484,7 +1484,7 @@ void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const Rend
}
}
-void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const Color &p_metallic_mask, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets) {
+void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -1579,10 +1579,6 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_projections[v].matrix[1][1]);
push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0];
push_constant.proj_info[3] = (1.0f + p_projections[v].matrix[1][2]) / p_projections[v].matrix[1][1];
- push_constant.metallic_mask[0] = CLAMP(p_metallic_mask.r * 255.0, 0, 255);
- push_constant.metallic_mask[1] = CLAMP(p_metallic_mask.g * 255.0, 0, 255);
- push_constant.metallic_mask[2] = CLAMP(p_metallic_mask.b * 255.0, 0, 255);
- push_constant.metallic_mask[3] = CLAMP(p_metallic_mask.a * 255.0, 0, 255);
ScreenSpaceReflectionMode mode = (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL;
RID shader = ssr.shader.version_get_shader(ssr.shader_version, mode);
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.h b/servers/rendering/renderer_rd/effects/ss_effects.h
index a60f3a48ab..d50319c46f 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.h
+++ b/servers/rendering/renderer_rd/effects/ss_effects.h
@@ -168,7 +168,7 @@ public:
};
void ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const Size2i &p_screen_size, const uint32_t p_view_count);
- void screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const Color &p_metallic_mask, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets);
+ void screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets);
void ssr_free(SSRRenderBuffers &p_ssr_buffers);
/* subsurface scattering */
@@ -465,10 +465,7 @@ private:
uint32_t orthogonal; // 4 - 52
float filter_mipmap_levels; // 4 - 56
uint32_t use_half_res; // 4 - 60
- uint8_t metallic_mask[4]; // 4 - 64
-
- uint32_t view_index; // 4 - 68
- uint32_t pad[3]; // 12 - 80
+ uint32_t view_index; // 4 - 64
// float projection[16]; // this is in our ScreenSpaceReflectionSceneData now
};
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index a0f6e69fd5..dec5e23558 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -124,7 +124,7 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RenderS
render_buffers = p_render_buffers;
ERR_FAIL_NULL(render_buffers);
- bool msaa_3d = render_buffers->get_msaa_3d();
+ RS::ViewportMSAA msaa_3d = render_buffers->get_msaa_3d();
if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
RD::DataFormat format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
@@ -1609,7 +1609,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
for (uint32_t v = 0; v < p_render_data->view_count; v++) {
specular_views[v] = rb_data->get_specular(v);
}
- _process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, Color(0, 0, 0, 1), p_render_data->environment, p_render_data->view_projection, p_render_data->view_eye_offset, rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED);
+ _process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, p_render_data->environment, p_render_data->view_projection, p_render_data->view_eye_offset, rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED);
RD::get_singleton()->draw_command_end_label();
} else {
//just mix specular back
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 78c83d1fb4..e2b06bc92f 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -1328,7 +1328,7 @@ void RendererSceneRenderRD::_process_sss(Ref<RenderSceneBuffersRD> p_render_buff
}
}
-void RendererSceneRenderRD::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, const Color &p_metallic_mask, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) {
+void RendererSceneRenderRD::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) {
ERR_FAIL_NULL(ss_effects);
ERR_FAIL_COND(p_render_buffers.is_null());
@@ -1355,7 +1355,7 @@ void RendererSceneRenderRD::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buff
texture_slices[v] = p_render_buffers->get_internal_texture(v);
depth_slices[v] = p_render_buffers->get_depth_texture(v);
}
- ss_effects->screen_space_reflection(p_render_buffers->ssr, texture_slices, p_normal_slices, ssr_roughness_quality, p_metallic_slices, p_metallic_mask, depth_slices, half_size, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), view_count, p_projections, p_eye_offsets);
+ ss_effects->screen_space_reflection(p_render_buffers->ssr, texture_slices, p_normal_slices, ssr_roughness_quality, p_metallic_slices, depth_slices, half_size, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), view_count, p_projections, p_eye_offsets);
copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), p_render_buffers->ssr.output, view_count);
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 76d2bc68fe..d47394989f 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -138,7 +138,7 @@ protected:
virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection);
- void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, const Color &p_metallic_mask, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
+ void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera);
void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform);
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index 246ef81cb2..9f86643e52 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -30,12 +30,7 @@ layout(push_constant, std430) uniform Params {
bool orthogonal;
float filter_mipmap_levels;
bool use_half_res;
- uint metallic_mask;
-
uint view_index;
- uint pad1;
- uint pad2;
- uint pad3;
}
params;
@@ -167,7 +162,7 @@ void main() {
if (depth > z_to) {
// if depth was surpassed
- if (depth <= max(z_to, z_from) + params.depth_tolerance && -depth < params.camera_z_far) {
+ if (depth <= max(z_to, z_from) + params.depth_tolerance && -depth < params.camera_z_far * 0.95) {
// check the depth tolerance and far clip
// check that normal is valid
found = true;
@@ -231,18 +226,20 @@ void main() {
}
}
- // Isn't this going to be overwritten after our endif?
- final_color = imageLoad(source_diffuse, ivec2((final_pos - 0.5) * pixel_size));
-
imageStore(blur_radius_image, ssC, vec4(blur_radius / 255.0)); //stored in r8
#endif // MODE_ROUGH
final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb, fade * margin_blend);
- //change blend by metallic
- vec4 metallic_mask = unpackUnorm4x8(params.metallic_mask);
- final_color.a *= dot(metallic_mask, texelFetch(source_metallic, ssC << 1, 0));
+ // Schlick term.
+ float metallic = texelFetch(source_metallic, ssC << 1, 0).w;
+ float f0 = mix(0.04, 1.0, metallic); // Assume a "specular" amount of 0.5
+ normal.y = -normal.y;
+ float m = clamp(1.0 - dot(normalize(normal), -view_dir), 0.0, 1.0);
+ float m2 = m * m;
+ m = m2 * m2 * m; // pow(m,5)
+ final_color.a *= f0 + (1.0 - f0) * m; // Fresnel Schlick term.
imageStore(ssr_image, ssC, final_color);
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index 576ec81124..84b65371e0 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -535,7 +535,9 @@ void RenderSceneBuffersRD::ensure_velocity() {
RD::TEXTURE_SAMPLES_8,
};
- create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, RD::DATA_FORMAT_R16G16_SFLOAT, msaa_usage_bits, ts[msaa_3d]);
+ RD::TextureSamples texture_samples = ts[msaa_3d];
+
+ create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, RD::DATA_FORMAT_R16G16_SFLOAT, msaa_usage_bits, texture_samples);
}
create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY, RD::DATA_FORMAT_R16G16_SFLOAT, usage_bits);