summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/list.h2
-rw-r--r--core/ustring.cpp16
-rw-r--r--doc/classes/Geometry2D.xml7
-rw-r--r--editor/animation_bezier_editor.cpp3
-rw-r--r--editor/editor_inspector.cpp104
-rw-r--r--editor/editor_inspector.h1
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/animation_tree_editor_plugin.h2
-rw-r--r--editor/scene_tree_dock.cpp12
-rw-r--r--modules/opensimplex/open_simplex_noise.cpp2
11 files changed, 133 insertions, 20 deletions
diff --git a/core/list.h b/core/list.h
index 6052a619fb..f850db5241 100644
--- a/core/list.h
+++ b/core/list.h
@@ -348,7 +348,7 @@ public:
* erase an element in the list, by iterator pointing to it. Return true if it was found/erased.
*/
bool erase(const Element *p_I) {
- if (_data) {
+ if (_data && p_I) {
bool ret = _data->erase(p_I);
if (_data->size_cache == 0) {
diff --git a/core/ustring.cpp b/core/ustring.cpp
index be242140a2..0b44f0c056 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -1650,8 +1650,9 @@ int64_t String::hex_to_int(bool p_with_prefix) const {
} else {
return 0;
}
-
- ERR_FAIL_COND_V_MSG(hex > INT64_MAX / 16, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ // Check for overflow/underflow, with special case to ensure INT64_MIN does not result in error
+ bool overflow = ((hex > INT64_MAX / 16) && (sign == 1 || (sign == -1 && hex != (INT64_MAX >> 4) + 1))) || (sign == -1 && hex == (INT64_MAX >> 4) + 1 && c > '0');
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
hex *= 16;
hex += n;
s++;
@@ -1690,8 +1691,9 @@ int64_t String::bin_to_int(bool p_with_prefix) const {
} else {
return 0;
}
-
- ERR_FAIL_COND_V_MSG(binary > INT64_MAX / 2, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ // Check for overflow/underflow, with special case to ensure INT64_MIN does not result in error
+ bool overflow = ((binary > INT64_MAX / 2) && (sign == 1 || (sign == -1 && binary != (INT64_MAX >> 1) + 1))) || (sign == -1 && binary == (INT64_MAX >> 1) + 1 && c > '0');
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
binary *= 2;
binary += n;
s++;
@@ -1713,7 +1715,8 @@ int64_t String::to_int() const {
for (int i = 0; i < to; i++) {
CharType c = operator[](i);
if (c >= '0' && c <= '9') {
- ERR_FAIL_COND_V_MSG(integer > INT64_MAX / 10, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as an integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8')));
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
integer *= 10;
integer += c - '0';
@@ -1741,7 +1744,8 @@ int64_t String::to_int(const char *p_str, int p_len) {
for (int i = 0; i < to; i++) {
char c = p_str[i];
if (c >= '0' && c <= '9') {
- ERR_FAIL_COND_V_MSG(integer > INT64_MAX / 10, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as an integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8')));
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as integer, provided value is " + (sign == 1 ? "too big." : "too small."));
integer *= 10;
integer += c - '0';
diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml
index ffd4bd108d..86dc8e864a 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -200,6 +200,13 @@
Inflates or deflates [code]polygon[/code] by [code]delta[/code] units (pixels). If [code]delta[/code] is positive, makes the polygon grow outward. If [code]delta[/code] is negative, shrinks the polygon inward. Returns an array of polygons because inflating/deflating may result in multiple discrete polygons. Returns an empty array if [code]delta[/code] is negative and the absolute value of it approximately exceeds the minimum bounding rectangle dimensions of the polygon.
Each polygon's vertices will be rounded as determined by [code]join_type[/code], see [enum PolyJoinType].
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
+ [b]Note:[/b] To translate the polygon's vertices specifically, use the [method Transform2D.xform] method:
+ [codeblock]
+ var polygon = PackedVector2Array([Vector2(0, 0), Vector2(100, 0), Vector2(100, 100), Vector2(0, 100)])
+ var offset = Vector2(50, 50)
+ polygon = Transform2D(0, offset).xform(polygon)
+ print(polygon) # prints [Vector2(50, 50), Vector2(150, 50), Vector2(150, 150), Vector2(50, 150)]
+ [/codeblock]
</description>
</method>
<method name="offset_polyline">
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index f880ece88b..e52f234218 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -31,6 +31,7 @@
#include "animation_bezier_editor.h"
#include "editor/editor_node.h"
+#include "editor_scale.h"
float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) {
float h = p_h;
@@ -539,7 +540,7 @@ void AnimationBezierTrackEdit::_play_position_draw() {
if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
Color color = get_theme_color("accent_color", "Editor");
- play_position->draw_line(Point2(px, 0), Point2(px, h), color);
+ play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE));
}
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index a8ded44323..cc58a0d5a0 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1504,9 +1504,9 @@ void EditorInspector::update_tree() {
String subgroup_base;
VBoxContainer *category_vbox = nullptr;
- List<PropertyInfo>
- plist;
+ List<PropertyInfo> plist;
object->get_property_list(&plist, true);
+ _update_script_class_properties(*object, plist);
HashMap<String, VBoxContainer *> item_path;
Map<VBoxContainer *, EditorInspectorSection *> section_map;
@@ -1572,7 +1572,28 @@ void EditorInspector::update_tree() {
category_vbox = nullptr; //reset
String type = p.name;
- category->icon = EditorNode::get_singleton()->get_class_icon(type, "Object");
+ if (!ClassDB::class_exists(type) && !ScriptServer::is_global_class(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) {
+ Ref<Script> s = ResourceLoader::load(p.hint_string, "Script");
+ String base_type;
+ if (s.is_valid()) {
+ base_type = s->get_instance_base_type();
+ }
+ while (s.is_valid()) {
+ StringName name = EditorNode::get_editor_data().script_class_get_name(s->get_path());
+ String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
+ if (name != StringName() && icon_path.length()) {
+ category->icon = ResourceLoader::load(icon_path, "Texture");
+ break;
+ }
+ s = s->get_base_script();
+ }
+ if (category->icon.is_null() && has_theme_icon(base_type, "EditorIcons")) {
+ category->icon = get_theme_icon(base_type, "EditorIcons");
+ }
+ }
+ if (category->icon.is_null()) {
+ category->icon = EditorNode::get_singleton()->get_class_icon(type, "Object");
+ }
category->label = type;
category->bg_color = get_theme_color("prop_category", "Editor");
@@ -2370,6 +2391,83 @@ void EditorInspector::_feature_profile_changed() {
update_tree();
}
+void EditorInspector::_update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const {
+ Ref<Script> script = p_object.get_script();
+ if (script.is_null()) {
+ return;
+ }
+
+ List<StringName> classes;
+ Map<StringName, String> paths;
+
+ // NodeC -> NodeB -> NodeA
+ while (script.is_valid()) {
+ String n = EditorNode::get_editor_data().script_class_get_name(script->get_path());
+ if (n.length()) {
+ classes.push_front(n);
+ } else {
+ n = script->get_path().get_file();
+ classes.push_front(n);
+ }
+ paths[n] = script->get_path();
+ script = script->get_base_script();
+ }
+
+ if (classes.empty()) {
+ return;
+ }
+
+ // Script Variables -> to insert: NodeC..B..A -> bottom (insert_here)
+ List<PropertyInfo>::Element *script_variables = NULL;
+ List<PropertyInfo>::Element *bottom = NULL;
+ List<PropertyInfo>::Element *insert_here = NULL;
+ for (List<PropertyInfo>::Element *E = r_list.front(); E; E = E->next()) {
+ PropertyInfo &pi = E->get();
+ if (pi.name != "Script Variables") {
+ continue;
+ }
+ script_variables = E;
+ bottom = r_list.insert_after(script_variables, PropertyInfo());
+ insert_here = bottom;
+ break;
+ }
+
+ Set<StringName> added;
+ for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
+ StringName name = E->get();
+ String path = paths[name];
+ Ref<Script> s = ResourceLoader::load(path, "Script");
+ List<PropertyInfo> props;
+ s->get_script_property_list(&props);
+
+ // Script Variables -> NodeA -> bottom (insert_here)
+ List<PropertyInfo>::Element *category = r_list.insert_before(insert_here, PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY));
+
+ // Script Variables -> NodeA -> A props... -> bottom (insert_here)
+ for (List<PropertyInfo>::Element *P = props.front(); P; P = P->next()) {
+ PropertyInfo &pi = P->get();
+ if (added.has(pi.name)) {
+ continue;
+ }
+ added.insert(pi.name);
+
+ r_list.insert_before(insert_here, pi);
+ }
+
+ // Script Variables -> NodeA (insert_here) -> A props... -> bottom
+ insert_here = category;
+ }
+
+ // NodeC -> C props... -> NodeB..C..
+ r_list.erase(script_variables);
+ List<PropertyInfo>::Element *to_delete = bottom->next();
+ while (to_delete && !(to_delete->get().usage & PROPERTY_USAGE_CATEGORY)) {
+ r_list.erase(to_delete);
+ to_delete = bottom->next();
+ }
+ r_list.erase(bottom);
+}
+
void EditorInspector::_bind_methods() {
ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change);
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 90d995e36d..615ad97766 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -332,6 +332,7 @@ class EditorInspector : public ScrollContainer {
void _vscroll_changed(double);
void _feature_profile_changed();
+ void _update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const;
bool _is_property_disabled_by_feature_profile(const StringName &p_property);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index b30d280023..5a298aabe7 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3780,8 +3780,6 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
if (icon.is_null()) {
icon = gui_base->get_theme_icon(ScriptServer::get_global_class_base(name), "EditorIcons");
}
-
- return icon;
}
const Map<String, Vector<EditorData::CustomType>> &p_map = EditorNode::get_editor_data().get_custom_types();
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index ec3e25f999..dc813896ff 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -238,7 +238,7 @@ AnimationTreeEditor::AnimationTreeEditor() {
add_child(memnew(HSeparator));
singleton = this;
- editor_base = memnew(PanelContainer);
+ editor_base = memnew(MarginContainer);
editor_base->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(editor_base);
diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h
index 25af81ea9b..79a010b0c0 100644
--- a/editor/plugins/animation_tree_editor_plugin.h
+++ b/editor/plugins/animation_tree_editor_plugin.h
@@ -55,7 +55,7 @@ class AnimationTreeEditor : public VBoxContainer {
HBoxContainer *path_hb;
AnimationTree *tree;
- PanelContainer *editor_base;
+ MarginContainer *editor_base;
Vector<String> button_path;
Vector<String> edited_path;
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index b8ac405f53..41b8baeb2f 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -354,11 +354,15 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
// Prefer nodes that inherit from the current scene root.
Node *current_edited_scene_root = EditorNode::get_singleton()->get_edited_scene();
if (current_edited_scene_root) {
- static const String preferred_types[] = { "Node2D", "Node3D", "Control" };
-
- StringName root_class = current_edited_scene_root->get_class_name();
+ String root_class = current_edited_scene_root->get_class_name();
+ static Vector<String> preferred_types;
+ if (preferred_types.empty()) {
+ preferred_types.push_back("Control");
+ preferred_types.push_back("Node2D");
+ preferred_types.push_back("Node3D");
+ }
- for (int i = 0; i < preferred_types->size(); i++) {
+ for (int i = 0; i < preferred_types.size(); i++) {
if (ClassDB::is_parent_class(root_class, preferred_types[i])) {
create_dialog->set_preferred_search_result_type(preferred_types[i]);
break;
diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp
index 00b3d47db9..b08219d258 100644
--- a/modules/opensimplex/open_simplex_noise.cpp
+++ b/modules/opensimplex/open_simplex_noise.cpp
@@ -110,7 +110,7 @@ Ref<Image> OpenSimplexNoise::get_image(int p_width, int p_height) {
for (int i = 0; i < p_height; i++) {
for (int j = 0; j < p_width; j++) {
- float v = get_noise_2d(i, j);
+ float v = get_noise_2d(j, i);
v = v * 0.5 + 0.5; // Normalize [0..1]
uint8_t value = uint8_t(CLAMP(v * 255.0, 0, 255));
wd8[(i * p_width + j) * 4 + 0] = value;