summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/config/project_settings.cpp19
-rw-r--r--core/input/input.cpp2
-rw-r--r--core/input/input_event.cpp15
-rw-r--r--core/input/input_event.h4
-rw-r--r--core/string/ustring.cpp11
-rw-r--r--core/variant/array.cpp6
-rw-r--r--core/variant/array.h1
-rw-r--r--core/variant/container_type_validate.h15
-rw-r--r--core/variant/variant_call.cpp1
-rw-r--r--core/variant/variant_op.cpp6
-rw-r--r--doc/classes/@GlobalScope.xml473
-rw-r--r--doc/classes/AABB.xml1
-rw-r--r--doc/classes/AStar2D.xml2
-rw-r--r--doc/classes/AStar3D.xml2
-rw-r--r--doc/classes/AnimationPlayer.xml2
-rw-r--r--doc/classes/Array.xml20
-rw-r--r--doc/classes/AudioStreamGeneratorPlayback.xml2
-rw-r--r--doc/classes/Basis.xml7
-rw-r--r--doc/classes/BoneMap.xml1
-rw-r--r--doc/classes/CPUParticles2D.xml36
-rw-r--r--doc/classes/CPUParticles3D.xml8
-rw-r--r--doc/classes/CheckBox.xml2
-rw-r--r--doc/classes/CheckButton.xml2
-rw-r--r--doc/classes/ClassDB.xml2
-rw-r--r--doc/classes/Color.xml15
-rw-r--r--doc/classes/ColorPicker.xml3
-rw-r--r--doc/classes/Control.xml6
-rw-r--r--doc/classes/CylinderShape3D.xml1
-rw-r--r--doc/classes/Dictionary.xml3
-rw-r--r--doc/classes/EditorFileDialog.xml3
-rw-r--r--doc/classes/EditorInterface.xml1
-rw-r--r--doc/classes/EditorPlugin.xml2
-rw-r--r--doc/classes/EditorProperty.xml1
-rw-r--r--doc/classes/EditorScript.xml1
-rw-r--r--doc/classes/EditorSettings.xml18
-rw-r--r--doc/classes/EditorSpinSlider.xml3
-rw-r--r--doc/classes/Engine.xml6
-rw-r--r--doc/classes/GPUParticles2D.xml2
-rw-r--r--doc/classes/GPUParticles3D.xml2
-rw-r--r--doc/classes/Image.xml8
-rw-r--r--doc/classes/InputEventScreenTouch.xml3
-rw-r--r--doc/classes/Mesh.xml2
-rw-r--r--doc/classes/MultiMesh.xml2
-rw-r--r--doc/classes/NodePath.xml2
-rw-r--r--doc/classes/ParticleProcessMaterial.xml2
-rw-r--r--doc/classes/PopupMenu.xml2
-rw-r--r--doc/classes/ProjectSettings.xml7
-rw-r--r--doc/classes/Projection.xml62
-rw-r--r--doc/classes/Resource.xml58
-rw-r--r--doc/classes/Script.xml2
-rw-r--r--doc/classes/Shape2D.xml6
-rw-r--r--doc/classes/SkeletonProfile.xml1
-rw-r--r--doc/classes/SkeletonProfileHumanoid.xml1
-rw-r--r--doc/classes/String.xml2
-rw-r--r--doc/classes/SurfaceTool.xml1
-rw-r--r--doc/classes/Texture2D.xml2
-rw-r--r--doc/classes/TileMap.xml2
-rw-r--r--doc/classes/VSlider.xml1
-rw-r--r--doc/classes/Viewport.xml6
-rw-r--r--doc/classes/ViewportTexture.xml1
-rw-r--r--doc/classes/VisibleOnScreenEnabler2D.xml7
-rw-r--r--doc/classes/VisualInstance3D.xml9
-rw-r--r--doc/classes/XRPose.xml4
-rw-r--r--doc/classes/XRServer.xml6
-rw-r--r--doc/classes/float.xml8
-rw-r--r--doc/classes/int.xml12
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp25
-rw-r--r--drivers/gles3/rasterizer_gles3.h2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp46
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h12
-rw-r--r--drivers/gles3/shader_gles3.cpp33
-rw-r--r--drivers/gles3/shader_gles3.h2
-rw-r--r--drivers/gles3/shaders/scene.glsl41
-rw-r--r--drivers/gles3/shaders/tonemap.glsl20
-rw-r--r--drivers/gles3/storage/config.cpp19
-rw-r--r--drivers/gles3/storage/config.h9
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp36
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp48
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h2
-rw-r--r--drivers/gles3/storage/texture_storage.cpp61
-rw-r--r--drivers/gles3/storage/texture_storage.h1
-rw-r--r--drivers/vulkan/vulkan_context.cpp26
-rw-r--r--editor/animation_track_editor.cpp2
-rw-r--r--editor/editor_resource_picker.cpp1
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp44
-rw-r--r--editor/plugins/node_3d_editor_plugin.h10
-rw-r--r--editor/plugins/script_text_editor.cpp126
-rw-r--r--editor/plugins/script_text_editor.h1
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp34
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp6
-rw-r--r--main/main.cpp2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml96
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp8
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml19
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml17
-rw-r--r--modules/gltf/gltf_state.cpp10
-rw-r--r--modules/gltf/gltf_state.h4
-rw-r--r--modules/gltf/structures/gltf_node.cpp10
-rw-r--r--modules/gltf/structures/gltf_node.h4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs8
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs2
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.cpp4
-rw-r--r--modules/multiplayer/scene_replication_interface.cpp6
-rw-r--r--modules/openxr/SCsub1
-rw-r--r--modules/openxr/doc_classes/OpenXRInterface.xml13
-rw-r--r--modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp123
-rw-r--r--modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h70
-rw-r--r--modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp28
-rw-r--r--modules/openxr/openxr_api.cpp39
-rw-r--r--modules/openxr/openxr_api.h8
-rw-r--r--modules/openxr/openxr_interface.cpp88
-rw-r--r--modules/openxr/openxr_interface.h5
-rw-r--r--modules/regex/doc_classes/RegEx.xml2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp11
-rw-r--r--modules/text_server_fb/text_server_fb.cpp10
-rw-r--r--modules/websocket/wsl_peer.cpp6
-rw-r--r--modules/webxr/godot_webxr.h2
-rw-r--r--modules/webxr/native/library_godot_webxr.js41
-rw-r--r--modules/webxr/webxr_interface_js.cpp3
-rw-r--r--platform/android/android_input_handler.cpp9
-rw-r--r--platform/android/android_input_handler.h4
-rw-r--r--platform/android/export/export_plugin.cpp26
-rw-r--r--platform/android/java/build.gradle12
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt25
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java26
-rw-r--r--platform/android/java_godot_lib_jni.cpp4
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/ios/display_server_ios.mm1
-rw-r--r--platform/ios/view_controller.mm12
-rw-r--r--platform/linuxbsd/display_server_x11.cpp19
-rw-r--r--platform/macos/display_server_macos.mm21
-rw-r--r--platform/macos/os_macos.mm4
-rw-r--r--platform/web/SCsub1
-rw-r--r--platform/web/display_server_web.cpp3
-rw-r--r--platform/web/godot_webgl2.h17
-rw-r--r--platform/web/js/libs/library_godot_webgl2.js52
-rw-r--r--platform/windows/display_server_windows.cpp21
-rw-r--r--platform/windows/display_server_windows.h1
-rw-r--r--scene/2d/light_2d.cpp5
-rw-r--r--scene/2d/tile_map.cpp154
-rw-r--r--scene/2d/tile_map.h6
-rw-r--r--scene/3d/node_3d.h4
-rw-r--r--scene/3d/visual_instance_3d.cpp6
-rw-r--r--scene/3d/visual_instance_3d.h2
-rw-r--r--scene/3d/xr_nodes.cpp4
-rw-r--r--scene/gui/color_picker.cpp2
-rw-r--r--scene/gui/control.cpp13
-rw-r--r--scene/gui/control.h7
-rw-r--r--scene/gui/scroll_bar.cpp2
-rw-r--r--scene/gui/text_edit.cpp6
-rw-r--r--scene/main/canvas_item.cpp30
-rw-r--r--scene/main/canvas_item.h5
-rw-r--r--scene/main/viewport.cpp1
-rw-r--r--scene/resources/shape_2d.cpp1
-rw-r--r--scene/resources/texture.cpp2
-rw-r--r--scene/resources/tile_set.h3
-rw-r--r--scene/resources/visual_shader_nodes.cpp2
-rw-r--r--servers/physics_3d/godot_body_3d.cpp2
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp3
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl15
-rw-r--r--tests/core/string/test_string.h4
-rw-r--r--tests/scene/test_text_edit.h26
-rw-r--r--thirdparty/glad/KHR/khrplatform.h27
-rw-r--r--thirdparty/glad/glad.c20
-rw-r--r--thirdparty/glad/glad/glad.h25
173 files changed, 2076 insertions, 750 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 001a351e0b..beef773699 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -153,8 +153,23 @@ const PackedStringArray ProjectSettings::_trim_to_supported_features(const Packe
#endif // TOOLS_ENABLED
String ProjectSettings::localize_path(const String &p_path) const {
- if (resource_path.is_empty() || p_path.begins_with("res://") || p_path.begins_with("user://") ||
- (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
+ if (resource_path.is_empty() || (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
+ return p_path.simplify_path();
+ }
+
+ // Check if we have a special path (like res://) or a protocol identifier.
+ int p = p_path.find("://");
+ bool found = false;
+ if (p > 0) {
+ found = true;
+ for (int i = 0; i < p; i++) {
+ if (!is_ascii_alphanumeric_char(p_path[i])) {
+ found = false;
+ break;
+ }
+ }
+ }
+ if (found) {
return p_path.simplify_path();
}
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 889c2a92fa..1321e40795 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -519,6 +519,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
touch_event.instantiate();
touch_event->set_pressed(mb->is_pressed());
touch_event->set_position(mb->get_position());
+ touch_event->set_double_tap(mb->is_double_click());
event_dispatch_function(touch_event);
}
}
@@ -580,6 +581,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
button_event->set_global_position(st->get_position());
button_event->set_pressed(st->is_pressed());
button_event->set_button_index(MouseButton::LEFT);
+ button_event->set_double_click(st->is_double_tap());
if (st->is_pressed()) {
button_event->set_button_mask(MouseButton(mouse_button_mask | MouseButton::MASK_LEFT));
} else {
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 38037eaf72..9dc071de9c 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -1162,6 +1162,13 @@ bool InputEventScreenTouch::is_pressed() const {
return pressed;
}
+void InputEventScreenTouch::set_double_tap(bool p_double_tap) {
+ double_tap = p_double_tap;
+}
+bool InputEventScreenTouch::is_double_tap() const {
+ return double_tap;
+}
+
Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
Ref<InputEventScreenTouch> st;
st.instantiate();
@@ -1170,6 +1177,7 @@ Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co
st->set_index(index);
st->set_position(p_xform.xform(pos + p_local_ofs));
st->set_pressed(pressed);
+ st->set_double_tap(double_tap);
return st;
}
@@ -1182,7 +1190,8 @@ String InputEventScreenTouch::as_text() const {
String InputEventScreenTouch::to_string() {
String p = pressed ? "true" : "false";
- return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s)", index, p, String(get_position()));
+ String double_tap_string = double_tap ? "true" : "false";
+ return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s), double_tap=%s", index, p, String(get_position()), double_tap_string);
}
void InputEventScreenTouch::_bind_methods() {
@@ -1195,9 +1204,13 @@ void InputEventScreenTouch::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventScreenTouch::set_pressed);
//ClassDB::bind_method(D_METHOD("is_pressed"),&InputEventScreenTouch::is_pressed);
+ ClassDB::bind_method(D_METHOD("set_double_tap", "double_tap"), &InputEventScreenTouch::set_double_tap);
+ ClassDB::bind_method(D_METHOD("is_double_tap"), &InputEventScreenTouch::is_double_tap);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "double_tap"), "set_double_tap", "is_double_tap");
}
///////////////////////////////////
diff --git a/core/input/input_event.h b/core/input/input_event.h
index bc3ec3e7ac..adbcb7cf68 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -353,6 +353,7 @@ class InputEventScreenTouch : public InputEventFromWindow {
int index = 0;
Vector2 pos;
bool pressed = false;
+ bool double_tap = false;
protected:
static void _bind_methods();
@@ -367,6 +368,9 @@ public:
void set_pressed(bool p_pressed);
virtual bool is_pressed() const override;
+ void set_double_tap(bool p_double_tap);
+ bool is_double_tap() const;
+
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual String as_text() const override;
virtual String to_string() override;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 671b06f0ed..c86c8316fe 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1567,10 +1567,11 @@ String String::num_real(double p_num, bool p_trailing) {
#else
int decimals = 6;
#endif
- // We want to align the digits to the above sane default, so we only
- // need to subtract log10 for numbers with a positive power of ten.
- if (p_num > 10) {
- decimals -= (int)floor(log10(p_num));
+ // We want to align the digits to the above sane default, so we only need
+ // to subtract log10 for numbers with a positive power of ten magnitude.
+ double abs_num = Math::abs(p_num);
+ if (abs_num > 10) {
+ decimals -= (int)floor(log10(abs_num));
}
return num(p_num, decimals);
}
@@ -3674,7 +3675,7 @@ String String::simplify_path() const {
if (p > 0) {
bool only_chars = true;
for (int i = 0; i < p; i++) {
- if (!is_ascii_char(s[i])) {
+ if (!is_ascii_alphanumeric_char(s[i])) {
only_chars = false;
break;
}
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 8b958814db..c6bbd43dc4 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -31,6 +31,7 @@
#include "array.h"
#include "container_type_validate.h"
+#include "core/math/math_funcs.h"
#include "core/object/class_db.h"
#include "core/object/script_language.h"
#include "core/templates/hashfuncs.h"
@@ -299,6 +300,11 @@ Variant Array::back() const {
return operator[](_p->array.size() - 1);
}
+Variant Array::pick_random() const {
+ ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");
+ return operator[](Math::rand() % _p->array.size());
+}
+
int Array::find(const Variant &p_value, int p_from) const {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find"), -1);
return _p->array.find(p_value, p_from);
diff --git a/core/variant/array.h b/core/variant/array.h
index 3d9a794969..ee265a9ffd 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -79,6 +79,7 @@ public:
Variant front() const;
Variant back() const;
+ Variant pick_random() const;
void sort();
void sort_custom(const Callable &p_callable);
diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h
index 6171c8c88f..427a337aab 100644
--- a/core/variant/container_type_validate.h
+++ b/core/variant/container_type_validate.h
@@ -79,9 +79,12 @@ struct ContainerTypeValidate {
return true;
}
- ERR_FAIL_COND_V_MSG(type != p_variant.get_type(), false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
if (type != p_variant.get_type()) {
- return false;
+ if (p_variant.get_type() == Variant::NIL && type == Variant::OBJECT) {
+ return true;
+ }
+
+ ERR_FAIL_V_MSG(false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
}
if (type != Variant::OBJECT) {
@@ -90,7 +93,7 @@ struct ContainerTypeValidate {
#ifdef DEBUG_ENABLED
ObjectID object_id = p_variant;
if (object_id == ObjectID()) {
- return true; //fine its null;
+ return true; // This is fine, it's null.
}
Object *object = ObjectDB::get_instance(object_id);
ERR_FAIL_COND_V_MSG(object == nullptr, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
@@ -101,7 +104,7 @@ struct ContainerTypeValidate {
}
#endif
if (class_name == StringName()) {
- return true; //all good, no class type requested
+ return true; // All good, no class type requested.
}
StringName obj_class = object->get_class_name();
@@ -110,12 +113,12 @@ struct ContainerTypeValidate {
}
if (script.is_null()) {
- return true; //all good
+ return true; // All good, no script requested.
}
Ref<Script> other_script = object->get_script();
- //check base script..
+ // Check base script..
ERR_FAIL_COND_V_MSG(other_script.is_null(), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
ERR_FAIL_COND_V_MSG(!other_script->inherits_script(script), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 900e3d8e77..ef4807ba71 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -2053,6 +2053,7 @@ static void _register_variant_builtin_methods() {
bind_method(Array, erase, sarray("value"), varray());
bind_method(Array, front, sarray(), varray());
bind_method(Array, back, sarray(), varray());
+ bind_method(Array, pick_random, sarray(), varray());
bind_method(Array, find, sarray("what", "from"), varray(0));
bind_method(Array, rfind, sarray("what", "from"), varray(-1));
bind_method(Array, find_last, sarray("value"), varray());
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 6cca7955ae..301fd00d26 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -384,10 +384,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorDivNZ<Vector2, Vector2i, double>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::FLOAT);
register_op<OperatorEvaluatorDivNZ<Vector2i, Vector2i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::INT);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, Vector2>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, double>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::FLOAT);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT);
-
register_op<OperatorEvaluatorDiv<Vector3, Vector3, Vector3>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::VECTOR3);
register_op<OperatorEvaluatorDiv<Vector3, Vector3, double>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::FLOAT);
register_op<OperatorEvaluatorDiv<Vector3, Vector3, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::INT);
@@ -498,8 +494,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorBitXor<int64_t, int64_t, int64_t>>(Variant::OP_BIT_XOR, Variant::INT, Variant::INT);
register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
- register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
-
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_EQUAL, Variant::NIL, Variant::NIL>>(Variant::OP_EQUAL, Variant::NIL, Variant::NIL);
register_op<OperatorEvaluatorEqual<bool, bool>>(Variant::OP_EQUAL, Variant::BOOL, Variant::BOOL);
register_op<OperatorEvaluatorEqual<int64_t, int64_t>>(Variant::OP_EQUAL, Variant::INT, Variant::INT);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 43f85fcdbc..9eeb69d824 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -16,7 +16,7 @@
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Returns the absolute value of a [Variant] parameter [param x] (i.e. non-negative value). Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Returns the absolute value of a [Variant] parameter [param x] (i.e. non-negative value). Variant types [int], [float], [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
var a = abs(-1)
# a is 1
@@ -114,7 +114,7 @@
<param index="3" name="end" type="float" />
<param index="4" name="t" type="float" />
<description>
- Returns the point at the given [param t] on a one-dimnesional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [param control_1], [param control_2], and [param end] points.
+ Returns the point at the given [param t] on a one-dimensional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [param control_1], [param control_2], and [param end] points.
</description>
</method>
<method name="bytes_to_var">
@@ -143,7 +143,7 @@
i = ceil(1.001) # i is 2.0
[/codeblock]
See also [method floor], [method round], and [method snapped].
- [b]Note:[/b] For better type safety, you can use [method ceilf], [method ceili], [method Vector2.ceil], [method Vector3.ceil] or [method Vector4.ceil] instead.
+ [b]Note:[/b] For better type safety, see [method ceilf], [method ceili], [method Vector2.ceil], [method Vector3.ceil] and [method Vector4.ceil].
</description>
</method>
<method name="ceilf">
@@ -151,7 +151,7 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] upward (towards positive infinity), returning the smallest whole number that is not less than [param x].
- A type-safe version of [method ceil], specialzied in floats.
+ A type-safe version of [method ceil], returning a [float].
</description>
</method>
<method name="ceili">
@@ -159,7 +159,7 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] upward (towards positive infinity), returning the smallest whole number that is not less than [param x].
- A type-safe version of [method ceil] that returns integer.
+ A type-safe version of [method ceil], returning an [int].
</description>
</method>
<method name="clamp">
@@ -168,7 +168,7 @@
<param index="1" name="min" type="Variant" />
<param index="2" name="max" type="Variant" />
<description>
- Clamps the [Variant] [param value] and returns a value not less than [param min] and not more than [param max]. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Clamps the [param value], returning a [Variant] not less than [param min] and not more than [param max]. Variant types [int], [float], [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
var a = clamp(-10, -1, 5)
# a is -1
@@ -196,15 +196,13 @@
<param index="1" name="min" type="float" />
<param index="2" name="max" type="float" />
<description>
- Clamps the float [param value] and returns a value not less than [param min] and not more than [param max].
+ Clamps the [param value], returning a [float] not less than [param min] and not more than [param max].
[codeblock]
var speed = 42.1
- # a is 20.0
- var a = clampf(speed, 1.0, 20.0)
+ var a = clampf(speed, 1.0, 20.5) # a is 20.5
speed = -10.0
- # a is -1.0
- a = clampf(speed, -1.0, 1.0)
+ var b = clampf(speed, -1.0, 1.0) # b is -1.0
[/codeblock]
</description>
</method>
@@ -214,15 +212,13 @@
<param index="1" name="min" type="int" />
<param index="2" name="max" type="int" />
<description>
- Clamps the integer [param value] and returns a value not less than [param min] and not more than [param max].
+ Clamps the [param value], returning an [int] not less than [param min] and not more than [param max].
[codeblock]
var speed = 42
- # a is 20
- var a = clampi(speed, 1, 20)
+ var a = clampi(speed, 1, 20) # a is 20
speed = -10
- # a is -1
- a = clampi(speed, -1, 1)
+ var b = clampi(speed, -1, 1) # b is -1
[/codeblock]
</description>
</method>
@@ -244,8 +240,7 @@
<description>
Returns the hyperbolic cosine of [param x] in radians.
[codeblock]
- # Prints 1.543081
- print(cosh(1))
+ print(cosh(1)) # Prints 1.543081
[/codeblock]
</description>
</method>
@@ -257,7 +252,7 @@
<param index="3" name="post" type="float" />
<param index="4" name="weight" type="float" />
<description>
- Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
+ Cubic interpolates between two values by the factor defined in [param weight] with [param pre] and [param post] values.
</description>
</method>
<method name="cubic_interpolate_angle">
@@ -268,7 +263,7 @@
<param index="3" name="post" type="float" />
<param index="4" name="weight" type="float" />
<description>
- Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
+ Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with [param pre] and [param post] values. See also [method lerp_angle].
</description>
</method>
<method name="cubic_interpolate_angle_in_time">
@@ -282,7 +277,7 @@
<param index="6" name="pre_t" type="float" />
<param index="7" name="post_t" type="float" />
<description>
- Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
+ Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with [param pre] and [param post] values. See also [method lerp_angle].
It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
</description>
</method>
@@ -297,8 +292,8 @@
<param index="6" name="pre_t" type="float" />
<param index="7" name="post_t" type="float" />
<description>
- Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
- It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
+ Cubic interpolates between two values by the factor defined in [param weight] with [param pre] and [param post] values.
+ It can perform smoother interpolation than [method cubic_interpolate] by the time values.
</description>
</method>
<method name="db_to_linear">
@@ -314,8 +309,7 @@
<description>
Converts an angle expressed in degrees to radians.
[codeblock]
- # r is 3.141593
- var r = deg_to_rad(180)
+ var r = deg_to_rad(180) # r is 3.141593
[/codeblock]
</description>
</method>
@@ -342,7 +336,13 @@
<return type="String" />
<param index="0" name="error" type="int" />
<description>
- Returns a human-readable name for the given error code.
+ Returns a human-readable name for the given [enum Error] code.
+ [codeblock]
+ print(OK) # Prints 0
+ print(error_string(OK)) # Prints OK
+ print(error_string(ERR_BUSY)) # Prints Busy
+ print(error_string(ERR_OUT_OF_MEMORY)) # Prints Out of memory
+ [/codeblock]
</description>
</method>
<method name="exp">
@@ -363,13 +363,11 @@
<description>
Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x]. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
[codeblock]
- # a is 2.0
- var a = floor(2.99)
- # a is -3.0
- a = floor(-2.99)
+ var a = floor(2.99) # a is 2.0
+ a = floor(-2.99) # a is -3.0
[/codeblock]
See also [method ceil], [method round], and [method snapped].
- [b]Note:[/b] For better type safety, you can use [method floorf], [method floori], [method Vector2.floor], [method Vector3.floor] or [method Vector4.floor] instead.
+ [b]Note:[/b] For better type safety, see [method floorf], [method floori], [method Vector2.floor], [method Vector3.floor] and [method Vector4.floor].
</description>
</method>
<method name="floorf">
@@ -377,7 +375,7 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x].
- A type-safe version of [method floor], specialzied in floats.
+ A type-safe version of [method floor], returning a [float].
</description>
</method>
<method name="floori">
@@ -385,7 +383,8 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x].
- Equivalent of doing [code]int(x)[/code].
+ A type-safe version of [method floor], returning an [int].
+ [b]Note:[/b] This function is [i]not[/i] the same as [code]int(x)[/code], which rounds towards 0.
</description>
</method>
<method name="fmod">
@@ -393,10 +392,9 @@
<param index="0" name="x" type="float" />
<param index="1" name="y" type="float" />
<description>
- Returns the floating-point remainder of [code]x/y[/code], keeping the sign of [param x].
+ Returns the floating-point remainder of [param x] divided by [param y], keeping the sign of [param x].
[codeblock]
- # Remainder is 1.5
- var remainder = fmod(7, 5.5)
+ var remainder = fmod(7, 5.5) # remainder is 1.5
[/codeblock]
For the integer remainder operation, use the [code]%[/code] operator.
</description>
@@ -406,21 +404,23 @@
<param index="0" name="x" type="float" />
<param index="1" name="y" type="float" />
<description>
- Returns the floating-point modulus of [code]x/y[/code] that wraps equally in positive and negative.
+ Returns the floating-point modulus of [param x] divided by [param y], wrapping equally in positive and negative.
[codeblock]
+ print(" (x) (fmod(x, 1.5)) (fposmod(x, 1.5))")
for i in 7:
- var x = 0.5 * i - 1.5
- print("%4.1f %4.1f %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
+ var x = i * 0.5 - 1.5
+ print("%4.1f %4.1f | %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
[/codeblock]
Produces:
[codeblock]
- -1.5 -0.0 0.0
- -1.0 -1.0 0.5
- -0.5 -0.5 1.0
- 0.0 0.0 0.0
- 0.5 0.5 0.5
- 1.0 1.0 1.0
- 1.5 0.0 0.0
+ (x) (fmod(x, 1.5)) (fposmod(x, 1.5))
+ -1.5 -0.0 | 0.0
+ -1.0 -1.0 | 0.5
+ -0.5 -0.5 | 1.0
+ 0.0 0.0 | 0.0
+ 0.5 0.5 | 0.5
+ 1.0 1.0 | 1.0
+ 1.5 0.0 | 0.0
[/codeblock]
</description>
</method>
@@ -428,7 +428,7 @@
<return type="int" />
<param index="0" name="variable" type="Variant" />
<description>
- Returns the integer hash of the variable passed.
+ Returns the integer hash of the passed [param variable].
[codeblock]
print(hash("a")) # Prints 177670
[/codeblock]
@@ -438,7 +438,7 @@
<return type="Object" />
<param index="0" name="instance_id" type="int" />
<description>
- Returns the Object that corresponds to [param instance_id]. All Objects have a unique instance ID.
+ Returns the [Object] that corresponds to [param instance_id]. All Objects have a unique instance ID. See also [method Object.get_instance_id].
[codeblock]
var foo = "bar"
func _ready():
@@ -458,12 +458,13 @@
[codeblock]
# The interpolation ratio in the `lerp()` call below is 0.75.
var middle = lerp(20, 30, 0.75)
- # `middle` is now 27.5.
+ # middle is now 27.5.
+
# Now, we pretend to have forgotten the original ratio and want to get it back.
var ratio = inverse_lerp(20, 30, 27.5)
- # `ratio` is now 0.75.
+ # ratio is now 0.75.
[/codeblock]
- See also [method lerp] which performs the reverse of this operation, and [method remap] to map a continuous series of values to another.
+ See also [method lerp], which performs the reverse of this operation, and [method remap] to map a continuous series of values to another.
</description>
</method>
<method name="is_equal_approx">
@@ -472,7 +473,7 @@
<param index="1" name="b" type="float" />
<description>
Returns [code]true[/code] if [param a] and [param b] are approximately equal to each other.
- Here, approximately equal means that [param a] and [param b] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
+ Here, "approximately equal" means that [param a] and [param b] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
Infinity values of the same sign are considered equal.
</description>
</method>
@@ -487,7 +488,7 @@
<return type="bool" />
<param index="0" name="x" type="float" />
<description>
- Returns whether [param x] is an infinity value (either positive infinity or negative infinity).
+ Returns [code]true[/code] if [param x] is either positive infinity or negative infinity.
</description>
</method>
<method name="is_instance_id_valid">
@@ -501,14 +502,14 @@
<return type="bool" />
<param index="0" name="instance" type="Variant" />
<description>
- Returns whether [param instance] is a valid object (e.g. has not been deleted from memory).
+ Returns [code]true[/code] if [param instance] is a valid Object (e.g. has not been deleted from memory).
</description>
</method>
<method name="is_nan">
<return type="bool" />
<param index="0" name="x" type="float" />
<description>
- Returns whether [param x] is a NaN ("Not a Number" or invalid) value.
+ Returns [code]true[/code] if [param x] is a NaN ("Not a Number" or invalid) value.
</description>
</method>
<method name="is_zero_approx">
@@ -516,7 +517,7 @@
<param index="0" name="x" type="float" />
<description>
Returns [code]true[/code] if [param x] is zero or almost zero.
- This method is faster than using [method is_equal_approx] with one value as zero.
+ This function is faster than using [method is_equal_approx] with one value as zero.
</description>
</method>
<method name="lerp">
@@ -525,13 +526,13 @@
<param index="1" name="to" type="Variant" />
<param index="2" name="weight" type="Variant" />
<description>
- Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. Use [method clamp] on the result of [method lerp] if this is not desired.
- Both [param from] and [param to] must have matching types. Supported types: [float], [Vector2], [Vector3], [Vector4], [Color], [Quaternion], [Basis].
+ Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. If this is not desired, use [method clamp] on the result of this function.
+ Both [param from] and [param to] must be the same type. Supported types: [float], [Vector2], [Vector3], [Vector4], [Color], [Quaternion], [Basis].
[codeblock]
lerp(0, 4, 0.75) # Returns 3.0
[/codeblock]
See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep]. See also [method remap] to map a continuous series of values to another.
- [b]Note:[/b] For better type safety, you can use [method lerpf], [method Vector2.lerp], [method Vector3.lerp], [method Vector4.lerp], [method Color.lerp], [method Quaternion.slerp] or [method Basis.slerp] instead.
+ [b]Note:[/b] For better type safety, use [method lerpf], [method Vector2.lerp], [method Vector3.lerp], [method Vector4.lerp], [method Color.lerp], [method Quaternion.slerp] or [method Basis.slerp].
</description>
</method>
<method name="lerp_angle">
@@ -540,7 +541,7 @@
<param index="1" name="to" type="float" />
<param index="2" name="weight" type="float" />
<description>
- Linearly interpolates between two angles (in radians) by a normalized value.
+ Linearly interpolates between two angles (in radians) by a [param weight] value between 0.0 and 1.0.
Similar to [method lerp], but interpolates correctly when the angles wrap around [constant @GDScript.TAU]. To perform eased interpolation with [method lerp_angle], combine it with [method ease] or [method smoothstep].
[codeblock]
extends Sprite
@@ -551,7 +552,7 @@
rotation = lerp_angle(min_angle, max_angle, elapsed)
elapsed += delta
[/codeblock]
- [b]Note:[/b] This method lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
+ [b]Note:[/b] This function lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
</description>
</method>
<method name="lerpf">
@@ -560,7 +561,7 @@
<param index="1" name="to" type="float" />
<param index="2" name="weight" type="float" />
<description>
- Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i].
+ Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. If this is not desired, use [method clampf] on the result of this function.
[codeblock]
lerp(0, 4, 0.75) # Returns 3.0
[/codeblock]
@@ -584,7 +585,7 @@
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Natural logarithm. The amount of time needed to reach a certain level of continuous growth.
+ Returns the natural logarithm of [param x]. This is the amount of time needed to reach a certain level of continuous growth.
[b]Note:[/b] This is not the same as the "log" function on most calculators, which uses a base 10 logarithm.
[codeblock]
log(10) # Returns 2.302585
@@ -595,7 +596,7 @@
<method name="max" qualifiers="vararg">
<return type="Variant" />
<description>
- Returns the maximum of the given values. This method can take any number of arguments.
+ Returns the maximum of the given values. This function can take any number of arguments.
[codeblock]
max(1, 7, 3, -6, 5) # Returns 7
[/codeblock]
@@ -606,9 +607,9 @@
<param index="0" name="a" type="float" />
<param index="1" name="b" type="float" />
<description>
- Returns the maximum of two float values.
+ Returns the maximum of two [float] values.
[codeblock]
- maxf(3.6, 24) # Returns 24.0
+ maxf(3.6, 24) # Returns 24.0
maxf(-3.99, -4) # Returns -3.99
[/codeblock]
</description>
@@ -618,9 +619,9 @@
<param index="0" name="a" type="int" />
<param index="1" name="b" type="int" />
<description>
- Returns the maximum of two int values.
+ Returns the maximum of two [int] values.
[codeblock]
- maxi(1, 2) # Returns 2
+ maxi(1, 2) # Returns 2
maxi(-3, -4) # Returns -3
[/codeblock]
</description>
@@ -628,7 +629,7 @@
<method name="min" qualifiers="vararg">
<return type="Variant" />
<description>
- Returns the minimum of the given values. This method can take any number of arguments.
+ Returns the minimum of the given values. This function can take any number of arguments.
[codeblock]
min(1, 7, 3, -6, 5) # Returns -6
[/codeblock]
@@ -639,9 +640,9 @@
<param index="0" name="a" type="float" />
<param index="1" name="b" type="float" />
<description>
- Returns the minimum of two float values.
+ Returns the minimum of two [float] values.
[codeblock]
- minf(3.6, 24) # Returns 3.6
+ minf(3.6, 24) # Returns 3.6
minf(-3.99, -4) # Returns -4.0
[/codeblock]
</description>
@@ -651,9 +652,9 @@
<param index="0" name="a" type="int" />
<param index="1" name="b" type="int" />
<description>
- Returns the minimum of two int values.
+ Returns the minimum of two [int] values.
[codeblock]
- mini(1, 2) # Returns 1
+ mini(1, 2) # Returns 1
mini(-3, -4) # Returns -4
[/codeblock]
</description>
@@ -667,8 +668,8 @@
Moves [param from] toward [param to] by the [param delta] value.
Use a negative [param delta] value to move away.
[codeblock]
- move_toward(5, 10, 4) # Returns 9
- move_toward(10, 5, 4) # Returns 6
+ move_toward(5, 10, 4) # Returns 9
+ move_toward(10, 5, 4) # Returns 6
move_toward(10, 5, -1.5) # Returns 11.5
[/codeblock]
</description>
@@ -677,17 +678,17 @@
<return type="int" />
<param index="0" name="value" type="int" />
<description>
- Returns the nearest equal or larger power of 2 for integer [param value].
+ Returns the nearest equal or larger power of 2 for the integer [param value].
In other words, returns the smallest value [code]a[/code] where [code]a = pow(2, n)[/code] such that [code]value &lt;= a[/code] for some non-negative integer [code]n[/code].
[codeblock]
nearest_po2(3) # Returns 4
nearest_po2(4) # Returns 4
nearest_po2(5) # Returns 8
- nearest_po2(0) # Returns 0 (this may not be what you expect)
- nearest_po2(-1) # Returns 0 (this may not be what you expect)
+ nearest_po2(0) # Returns 0 (this may not be expected)
+ nearest_po2(-1) # Returns 0 (this may not be expected)
[/codeblock]
- [b]Warning:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for non-positive values of [param value] (in reality, 1 is the smallest integer power of 2).
+ [b]Warning:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for negative values of [param value] (in reality, 1 is the smallest integer power of 2).
</description>
</method>
<method name="pingpong">
@@ -695,18 +696,18 @@
<param index="0" name="value" type="float" />
<param index="1" name="length" type="float" />
<description>
- Returns the [param value] wrapped between [code]0[/code] and the [param length]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [param length] side (like a triangle wave). If [param length] is less than zero, it becomes positive.
+ Wraps [param value] between [code]0[/code] and the [param length]. If the limit is reached, the next value the function returns is decreased to the [code]0[/code] side or increased to the [param length] side (like a triangle wave). If [param length] is less than zero, it becomes positive.
[codeblock]
- pingpong(-3.0, 3.0) # Returns 3
- pingpong(-2.0, 3.0) # Returns 2
- pingpong(-1.0, 3.0) # Returns 1
- pingpong(0.0, 3.0) # Returns 0
- pingpong(1.0, 3.0) # Returns 1
- pingpong(2.0, 3.0) # Returns 2
- pingpong(3.0, 3.0) # Returns 3
- pingpong(4.0, 3.0) # Returns 2
- pingpong(5.0, 3.0) # Returns 1
- pingpong(6.0, 3.0) # Returns 0
+ pingpong(-3.0, 3.0) # Returns 3.0
+ pingpong(-2.0, 3.0) # Returns 2.0
+ pingpong(-1.0, 3.0) # Returns 1.0
+ pingpong(0.0, 3.0) # Returns 0.0
+ pingpong(1.0, 3.0) # Returns 1.0
+ pingpong(2.0, 3.0) # Returns 2.0
+ pingpong(3.0, 3.0) # Returns 3.0
+ pingpong(4.0, 3.0) # Returns 2.0
+ pingpong(5.0, 3.0) # Returns 1.0
+ pingpong(6.0, 3.0) # Returns 0.0
[/codeblock]
</description>
</method>
@@ -715,20 +716,22 @@
<param index="0" name="x" type="int" />
<param index="1" name="y" type="int" />
<description>
- Returns the integer modulus of [code]x/y[/code] that wraps equally in positive and negative.
+ Returns the integer modulus of [param x] divided by [param y] that wraps equally in positive and negative.
[codeblock]
+ print("#(i) (i % 3) (posmod(i, 3))")
for i in range(-3, 4):
- print("%2d %2d %2d" % [i, i % 3, posmod(i, 3)])
+ print("%2d %2d | %2d" % [i, i % 3, posmod(i, 3)])
[/codeblock]
Produces:
[codeblock]
- -3 0 0
- -2 -2 1
- -1 -1 2
- 0 0 0
- 1 1 1
- 2 2 2
- 3 0 0
+ (i) (i % 3) (posmod(i, 3))
+ -3 0 | 0
+ -2 -2 | 1
+ -1 -1 | 2
+ 0 0 | 0
+ 1 1 | 1
+ 2 2 | 2
+ 3 0 | 0
[/codeblock]
</description>
</method>
@@ -738,6 +741,7 @@
<param index="1" name="exp" type="float" />
<description>
Returns the result of [param base] raised to the power of [param exp].
+ In GDScript, this is the equivalent of the [code]**[/code] operator.
[codeblock]
pow(2, 5) # Returns 32
[/codeblock]
@@ -750,7 +754,7 @@
var a = [1, 2, 3]
print("a", "b", a) # Prints ab[1, 2, 3]
[/codeblock]
- [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
+ [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print] or [method print_rich]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
</description>
</method>
<method name="print_rich" qualifiers="vararg">
@@ -778,11 +782,12 @@
</method>
<method name="printraw" qualifiers="vararg">
<description>
- Prints one or more arguments to strings in the best way possible to console. No newline is added at the end.
+ Prints one or more arguments to strings in the best way possible to console. Unlike [method print], no newline is automatically added at the end.
[codeblock]
printraw("A")
printraw("B")
- # Prints AB
+ printraw("C")
+ # Prints ABC
[/codeblock]
[b]Note:[/b] Due to limitations with Godot's built-in console, this only prints to the terminal. If you need to print in the editor, use another method, such as [method print].
</description>
@@ -809,7 +814,7 @@
[codeblock]
push_error("test error") # Prints "test error" to debugger and terminal as error call
[/codeblock]
- [b]Note:[/b] Errors printed this way will not pause project execution. To print an error message and pause project execution in debug builds, use [code]assert(false, "test error")[/code] instead.
+ [b]Note:[/b] This function does not pause project execution. To print an error message and pause project execution in debug builds, use [code]assert(false, "test error")[/code] instead.
</description>
</method>
<method name="push_warning" qualifiers="vararg">
@@ -827,6 +832,8 @@
Converts an angle expressed in radians to degrees.
[codeblock]
rad_to_deg(0.523599) # Returns 30
+ rad_to_deg(PI) # Returns 180
+ rad_to_deg(PI * 2) # Returns 360
[/codeblock]
</description>
</method>
@@ -834,7 +841,14 @@
<return type="PackedInt64Array" />
<param index="0" name="seed" type="int" />
<description>
- Random from seed: pass a [param seed], and an array with both number and new seed is returned. "Seed" here refers to the internal state of the pseudo random number generator. The internal state of the current implementation is 64 bits.
+ Given a [param seed], returns a [PackedInt64Array] of size [code]2[/code], where its first element is the randomised [int] value, and the second element is the same as [param seed]. Passing the same [param seed] consistently returns the same array.
+ [b]Note:[/b] "Seed" here refers to the internal state of the pseudo random number generator, currently implemented as a 64 bit integer.
+ [codeblock]
+ var a = rand_from_seed(4)
+
+ print(a[0]) # Prints 2879024997
+ print(a[1]) # Prints 4
+ [/codeblock]
</description>
</method>
<method name="randf">
@@ -851,9 +865,10 @@
<param index="0" name="from" type="float" />
<param index="1" name="to" type="float" />
<description>
- Returns a random floating point value on the interval between [param from] and [param to] (inclusive).
+ Returns a random floating point value between [param from] and [param to] (inclusive).
[codeblock]
- prints(randf_range(-10, 10), randf_range(-10, 10)) # Prints e.g. -3.844535 7.45315
+ randf_range(0, 20.5) # Returns e.g. 7.45315
+ randf_range(-10, 10) # Returns e.g. -3.844535
[/codeblock]
</description>
</method>
@@ -884,15 +899,15 @@
<description>
Returns a random signed 32-bit integer between [param from] and [param to] (inclusive). If [param to] is lesser than [param from], they are swapped.
[codeblock]
- print(randi_range(0, 1)) # Prints 0 or 1
- print(randi_range(-10, 1000)) # Prints any number from -10 to 1000
+ randi_range(0, 1) # Returns either 0 or 1
+ randi_range(-10, 1000) # Returns random integer between -10 and 1000
[/codeblock]
</description>
</method>
<method name="randomize">
<description>
- Randomizes the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.
- [b]Note:[/b] This method is called automatically when the project is run. If you need to fix the seed to have reproducible results, use [method seed] to initialize the random number generator.
+ Randomizes the seed (or the internal state) of the random number generator. The current implementation uses a number based on the device's time.
+ [b]Note:[/b] This function is called automatically when the project is run. If you need to fix the seed to have consistent, reproducible results, use [method seed] to initialize the random number generator.
</description>
</method>
<method name="remap">
@@ -903,63 +918,67 @@
<param index="3" name="ostart" type="float" />
<param index="4" name="ostop" type="float" />
<description>
- Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. Use [method clamp] on the result of [method remap] if this is not desired.
+ Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. If this is not desired, use [method clamp] on the result of this function.
[codeblock]
remap(75, 0, 100, -1, 1) # Returns 0.5
[/codeblock]
- For complex use cases where you need multiple ranges, consider using [Curve] or [Gradient] instead.
+ For complex use cases where multiple ranges are needed, consider using [Curve] or [Gradient] instead.
</description>
</method>
<method name="rid_allocate_id">
<return type="int" />
<description>
- Allocate a unique ID which can be used by the implementation to construct a RID. This is used mainly from native extensions to implement servers.
+ Allocates a unique ID which can be used by the implementation to construct a RID. This is used mainly from native extensions to implement servers.
</description>
</method>
<method name="rid_from_int64">
<return type="RID" />
<param index="0" name="base" type="int" />
<description>
- Create a RID from an int64. This is used mainly from native extensions to build servers.
+ Creates a RID from a [param base]. This is used mainly from native extensions to build servers.
</description>
</method>
<method name="round">
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from 0. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
[codeblock]
round(2.4) # Returns 2
round(2.5) # Returns 3
round(2.6) # Returns 3
[/codeblock]
See also [method floor], [method ceil], and [method snapped].
- [b]Note:[/b] For better type safety, you can use [method roundf], [method roundi], [method Vector2.round], [method Vector3.round] or [method Vector4.round] instead.
+ [b]Note:[/b] For better type safety, use [method roundf], [method roundi], [method Vector2.round], [method Vector3.round] or [method Vector4.round], instead.
</description>
</method>
<method name="roundf">
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero.
- A type-safe version of [method round], specialzied in floats.
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from 0.
+ A type-safe version of [method round], returning a [float].
</description>
</method>
<method name="roundi">
<return type="int" />
<param index="0" name="x" type="float" />
<description>
- Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero.
- A type-safe version of [method round] that returns integer.
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from 0.
+ A type-safe version of [method round], returning an [int].
</description>
</method>
<method name="seed">
<param index="0" name="base" type="int" />
<description>
- Sets seed for the random number generator.
+ Sets the seed for the random number generator to [param base]. Setting the seed manually can ensure consistent, repeatable results for most random functions.
[codeblock]
- var my_seed = "Godot Rocks"
- seed(my_seed.hash())
+ var my_seed = "Godot Rocks".hash()
+ seed(my_seed)
+ var a = randf() + randi()
+ seed(my_seed)
+ var b = randf() + randi()
+ # a and b are now identical
[/codeblock]
</description>
</method>
@@ -967,7 +986,7 @@
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Returns the sign of [param x] as same type of [Variant] as [param x] with each component being -1, 0 and 1 for each negative, zero and positive values respectivelu. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Returns the sign of [param x] as same type of [Variant] as [param x] with each component being -1, 0 and 1 for each negative, zero and positive values respectively. Variant types [int], [float], [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
sign(-6.0) # Returns -1
sign(0.0) # Returns 0
@@ -981,11 +1000,11 @@
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Returns the sign of [param x] as a float: -1.0 or 1.0. Returns 0.0 if [param x] is 0.
+ Returns the sign of [param x] as a [float]: -1.0 or 1.0. Returns 0.0 if [param x] is 0.0.
[codeblock]
- sign(-6.0) # Returns -1.0
+ sign(-6.5) # Returns -1.0
sign(0.0) # Returns 0.0
- sign(6.0) # Returns 1.0
+ sign(6.5) # Returns 1.0
[/codeblock]
</description>
</method>
@@ -993,7 +1012,7 @@
<return type="int" />
<param index="0" name="x" type="int" />
<description>
- Returns the sign of [param x] as an integer: -1 or 1. Returns 0 if [param x] is 0.
+ Returns the sign of [param x] as an [int]: -1 or 1. Returns 0 if [param x] is 0.
[codeblock]
sign(-6) # Returns -1
sign(0) # Returns 0
@@ -1047,7 +1066,7 @@
<param index="0" name="x" type="float" />
<param index="1" name="step" type="float" />
<description>
- Snaps float value [param x] to a given [param step]. This can also be used to round a floating point number to an arbitrary number of decimals.
+ Snaps the float value [param x] to a given [param step]. This can also be used to round a floating point number to an arbitrary number of decimals.
[codeblock]
snapped(100, 32) # Returns 96
snapped(3.14159, 0.01) # Returns 3.14
@@ -1061,9 +1080,11 @@
<description>
Returns the square root of [param x], where [param x] is a non-negative number.
[codeblock]
- sqrt(9) # Returns 3
+ sqrt(9) # Returns 3
+ sqrt(10.24) # Returns 3.2
+ sqrt(-1) # Returns NaN
[/codeblock]
- [b]Note:[/b] Negative values of [param x] return NaN. If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#.
+ [b]Note:[/b] Negative values of [param x] return NaN ("Not a Number"). in C#, if you need negative inputs, use [code]System.Numerics.Complex[/code].
</description>
</method>
<method name="step_decimals">
@@ -1072,30 +1093,27 @@
<description>
Returns the position of the first non-zero digit, after the decimal point. Note that the maximum return value is 10, which is a design decision in the implementation.
[codeblock]
- # n is 0
- var n = step_decimals(5)
- # n is 4
- n = step_decimals(1.0005)
- # n is 9
- n = step_decimals(0.000000005)
+ var n = step_decimals(5) # n is 0
+ n = step_decimals(1.0005) # n is 4
+ n = step_decimals(0.000000005) # n is 9
[/codeblock]
</description>
</method>
<method name="str" qualifiers="vararg">
<return type="String" />
<description>
- Converts one or more arguments of any type to string in the best way possible.
+ Converts one or more arguments of any [Variant] type to [String] in the best way possible.
</description>
</method>
<method name="str_to_var">
<return type="Variant" />
<param index="0" name="string" type="String" />
<description>
- Converts a formatted [param string] that was returned by [method var_to_str] to the original value.
+ Converts a formatted [param string] that was returned by [method var_to_str] to the original [Variant].
[codeblock]
- var a = '{ "a": 1, "b": 2 }'
- var b = str_to_var(a)
- print(b["a"]) # Prints 1
+ var a = '{ "a": 1, "b": 2 }' # a is a String
+ var b = str_to_var(a) # b is a Dictionary
+ print(b["a"]) # Prints 1
[/codeblock]
</description>
</method>
@@ -1116,7 +1134,7 @@
Returns the hyperbolic tangent of [param x].
[codeblock]
var a = log(2.0) # Returns 0.693147
- tanh(a) # Returns 0.6
+ tanh(a) # Returns 0.6
[/codeblock]
</description>
</method>
@@ -1124,7 +1142,7 @@
<return type="int" />
<param index="0" name="variable" type="Variant" />
<description>
- Returns the internal type of the given Variant object, using the [enum Variant.Type] values.
+ Returns the internal type of the given [param variable], using the [enum Variant.Type] values.
[codeblock]
var json = JSON.new()
json.parse('["a", "b", "c"]')
@@ -1148,19 +1166,19 @@
<return type="PackedByteArray" />
<param index="0" name="variable" type="Variant" />
<description>
- Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include code). Deserialization can be done with [method bytes_to_var_with_objects].
+ Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include executable code). Deserialization can be done with [method bytes_to_var_with_objects].
</description>
</method>
<method name="var_to_str">
<return type="String" />
<param index="0" name="variable" type="Variant" />
<description>
- Converts a Variant [param variable] to a formatted string that can later be parsed using [method str_to_var].
+ Converts a [Variant] [param variable] to a formatted [String] that can then be parsed using [method str_to_var].
[codeblock]
a = { "a": 1, "b": 2 }
print(var_to_str(a))
[/codeblock]
- prints
+ Prints:
[codeblock]
{
"a": 1,
@@ -1173,7 +1191,7 @@
<return type="Variant" />
<param index="0" name="obj" type="Variant" />
<description>
- Returns a weak reference to an object, or [code]null[/code] if the argument is invalid.
+ Returns a weak reference to an object, or [code]null[/code] if [param obj] is invalid.
A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else. However, until the object is actually destroyed the weak reference may return the object even if there are no strong references to it.
</description>
</method>
@@ -1183,9 +1201,8 @@
<param index="1" name="min" type="Variant" />
<param index="2" name="max" type="Variant" />
<description>
- Wraps the [Variant] [param value] between [param min] and [param max].
- Usable for creating loop-alike behavior or infinite surfaces.
- Variant types [int] and [float] (real) are supported. If any of the argument is [float] the result will be [float], otherwise it is [int].
+ Wraps the [Variant] [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
+ Variant types [int] and [float] are supported. If any of the arguments is [float] this function returns a [float], otherwise it returns an [int].
[codeblock]
var a = wrap(4, 5, 10)
# a is 9 (int)
@@ -1204,8 +1221,7 @@
<param index="1" name="min" type="float" />
<param index="2" name="max" type="float" />
<description>
- Wraps float [param value] between [param min] and [param max].
- Usable for creating loop-alike behavior or infinite surfaces.
+ Wraps the float [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
[codeblock]
# Infinite loop between 5.0 and 9.9
value = wrapf(value + 0.1, 5.0, 10.0)
@@ -1228,8 +1244,7 @@
<param index="1" name="min" type="int" />
<param index="2" name="max" type="int" />
<description>
- Wraps integer [param value] between [param min] and [param max].
- Usable for creating loop-alike behavior or infinite surfaces.
+ Wraps the integer [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
[codeblock]
# Infinite loop between 5 and 9
frame = wrapi(frame + 1, 5, 10)
@@ -1290,6 +1305,7 @@
The [Marshalls] singleton.
</member>
<member name="NativeExtensionManager" type="NativeExtensionManager" setter="" getter="">
+ The [NativeExtensionManager] singleton.
</member>
<member name="NavigationMeshGenerator" type="NavigationMeshGenerator" setter="" getter="">
The [NavigationMeshGenerator] singleton.
@@ -1384,8 +1400,10 @@
General horizontal alignment, usually used for [Separator], [ScrollBar], [Slider], etc.
</constant>
<constant name="CLOCKWISE" value="0" enum="ClockDirection">
+ Clockwise rotation. Used by some methods (e.g. [method Image.rotate_90]).
</constant>
<constant name="COUNTERCLOCKWISE" value="1" enum="ClockDirection">
+ Counter-clockwise rotation. Used by some methods (e.g. [method Image.rotate_90]).
</constant>
<constant name="HORIZONTAL_ALIGNMENT_LEFT" value="0" enum="HorizontalAlignment">
Horizontal left alignment, usually for text-derived classes.
@@ -1880,34 +1898,34 @@
/ key.
</constant>
<constant name="KEY_0" value="48" enum="Key">
- Number 0.
+ Number 0 key.
</constant>
<constant name="KEY_1" value="49" enum="Key">
- Number 1.
+ Number 1 key.
</constant>
<constant name="KEY_2" value="50" enum="Key">
- Number 2.
+ Number 2 key.
</constant>
<constant name="KEY_3" value="51" enum="Key">
- Number 3.
+ Number 3 key.
</constant>
<constant name="KEY_4" value="52" enum="Key">
- Number 4.
+ Number 4 key.
</constant>
<constant name="KEY_5" value="53" enum="Key">
- Number 5.
+ Number 5 key.
</constant>
<constant name="KEY_6" value="54" enum="Key">
- Number 6.
+ Number 6 key.
</constant>
<constant name="KEY_7" value="55" enum="Key">
- Number 7.
+ Number 7 key.
</constant>
<constant name="KEY_8" value="56" enum="Key">
- Number 8.
+ Number 8 key.
</constant>
<constant name="KEY_9" value="57" enum="Key">
- Number 9.
+ Number 9 key.
</constant>
<constant name="KEY_COLON" value="58" enum="Key">
: key.
@@ -2267,10 +2285,10 @@
Enum value which doesn't correspond to any mouse button. This is used to initialize [enum MouseButton] properties with a generic state.
</constant>
<constant name="MOUSE_BUTTON_LEFT" value="1" enum="MouseButton">
- Primary mouse button, usually the left button.
+ Primary mouse button, usually assigned to the left button.
</constant>
<constant name="MOUSE_BUTTON_RIGHT" value="2" enum="MouseButton">
- Secondary mouse button, usually the right button.
+ Secondary mouse button, usually assigned to the right button.
</constant>
<constant name="MOUSE_BUTTON_MIDDLE" value="3" enum="MouseButton">
Middle mouse button.
@@ -2288,10 +2306,10 @@
Mouse wheel right button (only present on some mice).
</constant>
<constant name="MOUSE_BUTTON_XBUTTON1" value="8" enum="MouseButton">
- Extra mouse button 1 (only present on some mice).
+ Extra mouse button 1. This is sometimes present, usually to the sides of the mouse.
</constant>
<constant name="MOUSE_BUTTON_XBUTTON2" value="9" enum="MouseButton">
- Extra mouse button 2 (only present on some mice).
+ Extra mouse button 2. This is sometimes present, usually to the sides of the mouse.
</constant>
<constant name="MOUSE_BUTTON_MASK_LEFT" value="1" enum="MouseButton">
Primary mouse button mask, usually for the left button.
@@ -2357,7 +2375,7 @@
Game controller D-pad right button.
</constant>
<constant name="JOY_BUTTON_MISC1" value="15" enum="JoyButton">
- Game controller SDL miscellaneous button. Corresponds to Xbox share button, PS5 microphone button, Nintendo capture button.
+ Game controller SDL miscellaneous button. Corresponds to Xbox share button, PS5 microphone button, Nintendo Switch capture button.
</constant>
<constant name="JOY_BUTTON_PADDLE1" value="16" enum="JoyButton">
Game controller SDL paddle 1 button.
@@ -2379,9 +2397,9 @@
</constant>
<constant name="JOY_BUTTON_MAX" value="128" enum="JoyButton">
The maximum number of game controller buttons supported by the engine. The actual limit may be lower on specific platforms:
- - Android: Up to 36 buttons.
- - Linux: Up to 80 buttons.
- - Windows and macOS: Up to 128 buttons.
+ - [b]Android:[/b] Up to 36 buttons.
+ - [b]Linux:[/b] Up to 80 buttons.
+ - [b]Windows[/b] and [b]macOS:[/b] Up to 128 buttons.
</constant>
<constant name="JOY_AXIS_INVALID" value="-1" enum="JoyAxis">
An invalid game controller axis.
@@ -2468,16 +2486,18 @@
MIDI system reset message. Reset all receivers in the system to power-up status. It should not be sent on power-up itself.
</constant>
<constant name="OK" value="0" enum="Error">
- Methods that return [enum Error] return [constant OK] when no error occurred. Note that many functions don't return an error code but will print error messages to standard output.
- Since [constant OK] has value 0, and all other failure codes are positive integers, it can also be used in boolean checks, e.g.:
+ Methods that return [enum Error] return [constant OK] when no error occurred.
+ Since [constant OK] has value 0, and all other error constants are positive integers, it can also be used in boolean checks. For example:
[codeblock]
- var err = method_that_returns_error()
- if err != OK:
- print("Failure!")
- # Or, equivalent:
- if err:
- print("Still failing!")
+ var error = method_that_returns_error()
+ if error != OK:
+ printerr("Failure!")
+
+ # Or, alternatively:
+ if error:
+ printerr("Still failing!")
[/codeblock]
+ [b]Note:[/b] Many functions do not return an error code, but will print error messages to standard output.
</constant>
<constant name="FAILED" value="1" enum="Error">
Generic error.
@@ -2615,100 +2635,101 @@
Skip error.
</constant>
<constant name="ERR_HELP" value="46" enum="Error">
- Help error.
+ Help error. Used internally when passing [code]--version[/code] or [code]--help[/code] as executable options.
</constant>
<constant name="ERR_BUG" value="47" enum="Error">
- Bug error.
+ Bug error, caused by an implementation issue in the method.
+ [b]Note:[/b] If a built-in method returns this code, please open an issue on [url=https://github.com/godotengine/godot/issues]the GitHub Issue Tracker[/url].
</constant>
<constant name="ERR_PRINTER_ON_FIRE" value="48" enum="Error">
- Printer on fire error. (This is an easter egg, no engine methods return this error code.)
+ Printer on fire error (This is an easter egg, no built-in methods return this error code).
</constant>
<constant name="PROPERTY_HINT_NONE" value="0" enum="PropertyHint">
- No hint for the edited property.
+ The property has no hint for the editor.
</constant>
<constant name="PROPERTY_HINT_RANGE" value="1" enum="PropertyHint">
- Hints that an integer or float property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_less"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_less"[/code].
+ Hints that an [int] or [float] property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_less"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_less"[/code].
Additionally, other keywords can be included: [code]"exp"[/code] for exponential range editing, [code]"radians"[/code] for editing radian angles in degrees, [code]"degrees"[/code] to hint at an angle and [code]"hide_slider"[/code] to hide the slider.
</constant>
<constant name="PROPERTY_HINT_ENUM" value="2" enum="PropertyHint">
- Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string.
+ Hints that an [int], [float], or [String] property is an enumerated value to pick in a list specified via a hint string.
The hint string is a comma separated list of names such as [code]"Hello,Something,Else"[/code]. Whitespaces are [b]not[/b] removed from either end of a name. For integer and float properties, the first name in the list has value 0, the next 1, and so on. Explicit values can also be specified by appending [code]:integer[/code] to the name, e.g. [code]"Zero,One,Three:3,Four,Six:6"[/code].
</constant>
<constant name="PROPERTY_HINT_ENUM_SUGGESTION" value="3" enum="PropertyHint">
- Hints that a string property can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code].
- Unlike [constant PROPERTY_HINT_ENUM] a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values.
+ Hints that a [String] property can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code].
+ Unlike [constant PROPERTY_HINT_ENUM], a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values.
</constant>
<constant name="PROPERTY_HINT_EXP_EASING" value="4" enum="PropertyHint">
- Hints that a float property should be edited via an exponential easing function. The hint string can include [code]"attenuation"[/code] to flip the curve horizontally and/or [code]"positive_only"[/code] to exclude in/out easing and limit values to be greater than or equal to zero.
+ Hints that a [float] property should be edited via an exponential easing function. The hint string can include [code]"attenuation"[/code] to flip the curve horizontally and/or [code]"positive_only"[/code] to exclude in/out easing and limit values to be greater than or equal to zero.
</constant>
<constant name="PROPERTY_HINT_LINK" value="5" enum="PropertyHint">
- Hints that a vector property should allow linking values (e.g. to edit both [code]x[/code] and [code]y[/code] together).
+ Hints that a vector property should allow its components to be linked. For example, this allows [member Vector2.x] and [member Vector2.y] to be edited together.
</constant>
<constant name="PROPERTY_HINT_FLAGS" value="6" enum="PropertyHint">
- Hints that an integer property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code].
+ Hints that an [int] property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code].
</constant>
<constant name="PROPERTY_HINT_LAYERS_2D_RENDER" value="7" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 2D render layers.
+ Hints that an [int] property is a bitmask using the optionally named 2D render layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="8" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 2D physics layers.
+ Hints that an [int] property is a bitmask using the optionally named 2D physics layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_2D_NAVIGATION" value="9" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 2D navigation layers.
+ Hints that an [int] property is a bitmask using the optionally named 2D navigation layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="10" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 3D render layers.
+ Hints that an [int] property is a bitmask using the optionally named 3D render layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="11" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 3D physics layers.
+ Hints that an [int] property is a bitmask using the optionally named 3D physics layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_3D_NAVIGATION" value="12" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 3D navigation layers.
+ Hints that an [int] property is a bitmask using the optionally named 3D navigation layers.
</constant>
<constant name="PROPERTY_HINT_FILE" value="13" enum="PropertyHint">
- Hints that a string property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
+ Hints that a [String] property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
</constant>
<constant name="PROPERTY_HINT_DIR" value="14" enum="PropertyHint">
- Hints that a string property is a path to a directory. Editing it will show a file dialog for picking the path.
+ Hints that a [String] property is a path to a directory. Editing it will show a file dialog for picking the path.
</constant>
<constant name="PROPERTY_HINT_GLOBAL_FILE" value="15" enum="PropertyHint">
- Hints that a string property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
+ Hints that a [String] property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards, like [code]"*.png,*.jpg"[/code].
</constant>
<constant name="PROPERTY_HINT_GLOBAL_DIR" value="16" enum="PropertyHint">
- Hints that a string property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path.
+ Hints that a [String] property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path.
</constant>
<constant name="PROPERTY_HINT_RESOURCE_TYPE" value="17" enum="PropertyHint">
Hints that a property is an instance of a [Resource]-derived type, optionally specified via the hint string (e.g. [code]"Texture2D"[/code]). Editing it will show a popup menu of valid resource types to instantiate.
</constant>
<constant name="PROPERTY_HINT_MULTILINE_TEXT" value="18" enum="PropertyHint">
- Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
+ Hints that a [String] property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
</constant>
<constant name="PROPERTY_HINT_EXPRESSION" value="19" enum="PropertyHint">
- Hints that a string property is an [Expression].
+ Hints that a [String] property is an [Expression].
</constant>
<constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="20" enum="PropertyHint">
- Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use.
+ Hints that a [String] property should show a placeholder text on its input field, if empty. The hint string is the placeholder text to use.
</constant>
<constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="21" enum="PropertyHint">
- Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited.
+ Hints that a [Color] property should be edited without affecting its transparency ([member Color.a] is not editable).
</constant>
<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="22" enum="PropertyHint">
- Hints that an image is compressed using lossy compression.
+ Hints that an image is compressed using lossy compression. The editor does not internally use this property hint.
</constant>
<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="23" enum="PropertyHint">
- Hints that an image is compressed using lossless compression.
+ Hints that an image is compressed using lossless compression. The editor does not internally use this property hint.
</constant>
<constant name="PROPERTY_HINT_OBJECT_ID" value="24" enum="PropertyHint">
</constant>
<constant name="PROPERTY_HINT_TYPE_STRING" value="25" enum="PropertyHint">
- Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance:
+ Hints that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For example:
[codeblock]
- hint_string = "%s:" % [TYPE_INT] # Array of inteters.
+ hint_string = "%s:" % [TYPE_INT] # Array of integers.
hint_string = "%s:%s:" % [TYPE_ARRAY, TYPE_REAL] # Two-dimensional array of floats.
hint_string = "%s/%s:Resource" % [TYPE_OBJECT, TYPE_OBJECT] # Array of resources.
hint_string = "%s:%s/%s:Resource" % [TYPE_ARRAY, TYPE_OBJECT, TYPE_OBJECT] # Two-dimensional array of resources.
[/codeblock]
- [b]Note:[/b] The final colon is required to specify for properly detecting built-in types.
+ [b]Note:[/b] The final colon is required for properly detecting built-in types.
</constant>
<constant name="PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE" value="26" enum="PropertyHint">
</constant>
@@ -2729,6 +2750,7 @@
<constant name="PROPERTY_HINT_PROPERTY_OF_SCRIPT" value="34" enum="PropertyHint">
</constant>
<constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="35" enum="PropertyHint">
+ Hints that a property's size (in bytes) is too big to be displayed, when debugging a running project. The debugger uses this hint internally.
</constant>
<constant name="PROPERTY_HINT_NODE_PATH_VALID_TYPES" value="36" enum="PropertyHint">
</constant>
@@ -2743,28 +2765,31 @@
<constant name="PROPERTY_HINT_ARRAY_TYPE" value="40" enum="PropertyHint">
</constant>
<constant name="PROPERTY_HINT_LOCALE_ID" value="42" enum="PropertyHint">
- Hints that a string property is a locale code. Editing it will show a locale dialog for picking language and country.
+ Hints that a [String] property is a locale code. Editing it will show a locale dialog for picking language and country.
</constant>
<constant name="PROPERTY_HINT_LOCALIZABLE_STRING" value="43" enum="PropertyHint">
- Hints that a dictionary property is string translation map. Dictionary keys are locale codes and, values are translated strings.
+ Hints that a [Dictionary] property is string translation map. Dictionary keys are locale codes and, values are translated strings.
</constant>
<constant name="PROPERTY_HINT_NODE_TYPE" value="44" enum="PropertyHint">
</constant>
<constant name="PROPERTY_HINT_HIDE_QUATERNION_EDIT" value="45" enum="PropertyHint">
- Hints that a quaternion property should disable the temporary euler editor.
+ Hints that a [Quaternion] property should disable the temporary euler editor.
</constant>
<constant name="PROPERTY_HINT_PASSWORD" value="46" enum="PropertyHint">
- Hints that a string property is a password, and every character is replaced with the secret character.
+ Hints that a [String] property is a password. Every character of the string is displayed as the secret character (typically [code]*[/code]).
+ An optional placeholder text can be shown on its input field, similarly to [constant PROPERTY_HINT_PLACEHOLDER_TEXT].
</constant>
<constant name="PROPERTY_HINT_MAX" value="47" enum="PropertyHint">
+ Represents the size of the [enum PropertyHint] enum.
</constant>
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
+ The property is not stored, and does not display in the editor. This is the default for non-exported properties.
</constant>
<constant name="PROPERTY_USAGE_STORAGE" value="2" enum="PropertyUsageFlags">
The property is serialized and saved in the scene file (default).
</constant>
<constant name="PROPERTY_USAGE_EDITOR" value="4" enum="PropertyUsageFlags">
- The property is shown in the editor inspector (default).
+ The property is shown in the editor Inspector (default).
</constant>
<constant name="PROPERTY_USAGE_CHECKABLE" value="8" enum="PropertyUsageFlags">
The property can be checked in the editor inspector.
@@ -2810,8 +2835,10 @@
<constant name="PROPERTY_USAGE_INTERNAL" value="524288" enum="PropertyUsageFlags">
</constant>
<constant name="PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE" value="1048576" enum="PropertyUsageFlags">
+ If the property is a [Resource], a new copy of it is always created when calling [method Node.duplicate] or [method Resource.duplicate].
</constant>
<constant name="PROPERTY_USAGE_HIGH_END_GFX" value="2097152" enum="PropertyUsageFlags">
+ The property is only shown in the editor if modern renderers are supported (GLES3 is excluded).
</constant>
<constant name="PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT" value="4194304" enum="PropertyUsageFlags">
</constant>
@@ -2826,9 +2853,10 @@
<constant name="PROPERTY_USAGE_EDITOR_BASIC_SETTING" value="134217728" enum="PropertyUsageFlags">
</constant>
<constant name="PROPERTY_USAGE_READ_ONLY" value="268435456" enum="PropertyUsageFlags">
- The property is read-only in the editor inspector.
+ The property is read-only in the editor Inspector.
</constant>
<constant name="PROPERTY_USAGE_ARRAY" value="536870912" enum="PropertyUsageFlags">
+ The property is an array.
</constant>
<constant name="PROPERTY_USAGE_DEFAULT" value="6" enum="PropertyUsageFlags">
Default usage (storage, editor and network).
@@ -2852,14 +2880,16 @@
Flag for a virtual method.
</constant>
<constant name="METHOD_FLAG_VARARG" value="16" enum="MethodFlags">
+ Flag for a method with a variable number of arguments.
</constant>
<constant name="METHOD_FLAG_STATIC" value="32" enum="MethodFlags">
+ Flag for a static method.
</constant>
<constant name="METHOD_FLAG_OBJECT_CORE" value="64" enum="MethodFlags">
- Used internally. Allows to not dump core virtuals such as [code]_notification[/code] to the JSON API.
+ Used internally. Allows to not dump core virtual methods (such as [method Object._notification]) to the JSON API.
</constant>
<constant name="METHOD_FLAGS_DEFAULT" value="1" enum="MethodFlags">
- Default method flags.
+ Default method flags (normal).
</constant>
<constant name="TYPE_NIL" value="0" enum="Variant.Type">
Variable is [code]null[/code].
@@ -2871,7 +2901,7 @@
Variable is of type [int].
</constant>
<constant name="TYPE_FLOAT" value="3" enum="Variant.Type">
- Variable is of type [float] (real).
+ Variable is of type [float].
</constant>
<constant name="TYPE_STRING" value="4" enum="Variant.Type">
Variable is of type [String].
@@ -2898,8 +2928,10 @@
Variable is of type [Transform2D].
</constant>
<constant name="TYPE_VECTOR4" value="12" enum="Variant.Type">
+ Variable is of type [Vector4].
</constant>
<constant name="TYPE_VECTOR4I" value="13" enum="Variant.Type">
+ Variable is of type [Vector4i].
</constant>
<constant name="TYPE_PLANE" value="14" enum="Variant.Type">
Variable is of type [Plane].
@@ -2917,6 +2949,7 @@
Variable is of type [Transform3D].
</constant>
<constant name="TYPE_PROJECTION" value="19" enum="Variant.Type">
+ Variable is of type [Projection].
</constant>
<constant name="TYPE_COLOR" value="20" enum="Variant.Type">
Variable is of type [Color].
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index 1ac3e6b64c..ca454cafa3 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -188,6 +188,7 @@
<param index="0" name="from" type="Vector3" />
<param index="1" name="dir" type="Vector3" />
<description>
+ Returns [code]true[/code] if the given ray intersects with this [AABB]. Ray length is infinite.
</description>
</method>
<method name="intersects_segment" qualifiers="const">
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index 6e76df647e..2414b068e6 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -271,7 +271,7 @@
<return type="void" />
<param index="0" name="num_nodes" type="int" />
<description>
- Reserves space internally for [param num_nodes] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
+ Reserves space internally for [param num_nodes] points, useful if you're adding a known large number of points at once, such as points on a grid. New capacity must be greater or equals to old capacity.
</description>
</method>
<method name="set_point_disabled">
diff --git a/doc/classes/AStar3D.xml b/doc/classes/AStar3D.xml
index 45b1019bab..4e8394195d 100644
--- a/doc/classes/AStar3D.xml
+++ b/doc/classes/AStar3D.xml
@@ -298,7 +298,7 @@
<return type="void" />
<param index="0" name="num_nodes" type="int" />
<description>
- Reserves space internally for [param num_nodes] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
+ Reserves space internally for [param num_nodes] points. Useful if you're adding a known large number of points at once, such as points on a grid. New capacity must be greater or equals to old capacity.
</description>
</method>
<method name="set_point_disabled">
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index c32cc5c5b8..bf5ac7fa9e 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -242,7 +242,7 @@
The process notification in which to update animations.
</member>
<member name="playback_speed" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- The speed scaling ratio. For instance, if this value is 1, then the animation plays at normal speed. If it's 0.5, then it plays at half speed. If it's 2, then it plays at double speed.
+ The speed scaling ratio. For example, if this value is 1, then the animation plays at normal speed. If it's 0.5, then it plays at half speed. If it's 2, then it plays at double speed.
</member>
<member name="reset_on_save" type="bool" setter="set_reset_on_save_enabled" getter="is_reset_on_save_enabled" default="true">
This is used by the editor. If set to [code]true[/code], the scene will be saved with the effects of the reset animation (the animation with the key [code]"RESET"[/code]) applied as if it had been seeked to time 0, with the editor keeping the values that the scene had before saving.
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index 047089c917..0f76639caf 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -58,6 +58,7 @@
<param index="2" name="class_name" type="StringName" />
<param index="3" name="script" type="Variant" />
<description>
+ Creates a typed array from the [param base] array. The base array can't be already typed. See [method set_typed] for more details.
</description>
</constructor>
<constructor name="Array">
@@ -315,16 +316,19 @@
<method name="get_typed_builtin" qualifiers="const">
<return type="int" />
<description>
+ Returns the [code]TYPE[/code] constant for a typed array. If the [Array] is not typed, returns [constant @GlobalScope.TYPE_NIL].
</description>
</method>
<method name="get_typed_class_name" qualifiers="const">
<return type="StringName" />
<description>
+ Returns a class name of a typed [Array] of type [constant @GlobalScope.TYPE_OBJECT].
</description>
</method>
<method name="get_typed_script" qualifiers="const">
<return type="Variant" />
<description>
+ Returns the script associated with a typed array tied to a class name.
</description>
</method>
<method name="has" qualifiers="const">
@@ -393,11 +397,13 @@
<method name="is_read_only" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if the array is read-only. See [method set_read_only]. Arrays are automatically read-only if declared with [code]const[/code] keyword.
</description>
</method>
<method name="is_typed" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if the array is typed. Typed arrays can only store elements of their associated type and provide type safety for the [code][][/code] operator. Methods of typed array still return [Variant].
</description>
</method>
<method name="map" qualifiers="const">
@@ -429,6 +435,16 @@
Returns the minimum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned.
</description>
</method>
+ <method name="pick_random" qualifiers="const">
+ <return type="Variant" />
+ <description>
+ Returns a random value from the target array.
+ [codeblock]
+ var array: Array[int] = [1, 2, 3, 4]
+ print(array.pick_random()) # Prints either of the four numbers.
+ [/codeblock]
+ </description>
+ </method>
<method name="pop_at">
<return type="Variant" />
<param index="0" name="position" type="int" />
@@ -517,6 +533,7 @@
<return type="void" />
<param index="0" name="enable" type="bool" />
<description>
+ Makes the [Array] read-only, i.e. disabled modifying of the array's elements. Does not apply to nested content, e.g. content of nested arrays.
</description>
</method>
<method name="set_typed">
@@ -525,6 +542,8 @@
<param index="1" name="class_name" type="StringName" />
<param index="2" name="script" type="Variant" />
<description>
+ Makes the [Array] typed. The [param type] should be one of the [@GlobalScope] [code]TYPE[/code] constants. [param class_name] is optional and can only be provided for [constant @GlobalScope.TYPE_OBJECT]. [param script] can only be provided if [param class_name] is not empty.
+ The method fails if an array is already typed.
</description>
</method>
<method name="shuffle">
@@ -610,6 +629,7 @@
<return type="bool" />
<param index="0" name="array" type="Array" />
<description>
+ Assigns a different [Array] to this array reference. It the array is typed, the new array's type must be compatible and its elements will be automatically converted.
</description>
</method>
</methods>
diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml
index 1c02dbd3ce..c16198c5c6 100644
--- a/doc/classes/AudioStreamGeneratorPlayback.xml
+++ b/doc/classes/AudioStreamGeneratorPlayback.xml
@@ -27,7 +27,7 @@
<method name="get_frames_available" qualifiers="const">
<return type="int" />
<description>
- Returns the number of audio data frames left to play. If this returned number reaches [code]0[/code], the audio will stop playing until frames are added again. Therefore, make sure your script can always generate and push new audio frames fast enough to avoid audio cracking.
+ Returns the number of frames that can be pushed to the audio sample data buffer without overflowing it. If the result is [code]0[/code], the buffer is full.
</description>
</method>
<method name="get_skips" qualifiers="const">
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index f499be34a0..0f1f4b57a9 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -70,6 +70,7 @@
<param index="0" name="euler" type="Vector3" />
<param index="1" name="order" type="int" default="2" />
<description>
+ Creates a [Basis] from the given [Vector3] representing Euler angles. [param order] determines in what order rotation components are applied. Defaults to [constant EULER_ORDER_YXZ].
</description>
</method>
<method name="from_scale" qualifiers="static">
@@ -197,16 +198,22 @@
</members>
<constants>
<constant name="EULER_ORDER_XYZ" value="0">
+ Euler angle composing/decomposing order where X component is first, then Y, then Z.
</constant>
<constant name="EULER_ORDER_XZY" value="1">
+ Euler angle composing/decomposing order where X component is first, then Z, then Y.
</constant>
<constant name="EULER_ORDER_YXZ" value="2">
+ Euler angle composing/decomposing order where Y component is first, then X, then Z.
</constant>
<constant name="EULER_ORDER_YZX" value="3">
+ Euler angle composing/decomposing order where Y component is first, then Z, then X.
</constant>
<constant name="EULER_ORDER_ZXY" value="4">
+ Euler angle composing/decomposing order where Z component is first, then X, then Y.
</constant>
<constant name="EULER_ORDER_ZYX" value="5">
+ Euler angle composing/decomposing order where Z component is first, then Y, then X.
</constant>
<constant name="IDENTITY" value="Basis(1, 0, 0, 0, 1, 0, 0, 0, 1)">
The identity basis, with no rotation or scaling applied.
diff --git a/doc/classes/BoneMap.xml b/doc/classes/BoneMap.xml
index f7a4845b7d..7135406d3c 100644
--- a/doc/classes/BoneMap.xml
+++ b/doc/classes/BoneMap.xml
@@ -8,6 +8,7 @@
By assigning the actual [Skeleton3D] bone name as the key value, it maps the [Skeleton3D] to the [SkeletonProfile].
</description>
<tutorials>
+ <link title="Retargeting 3D Skeletons">$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html</link>
</tutorials>
<methods>
<method name="find_profile_bone_name" qualifiers="const">
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index 906789d09f..314e46d9d0 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -29,12 +29,14 @@
<return type="float" />
<param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<description>
+ Returns the maximum value range for the given parameter.
</description>
</method>
<method name="get_param_min" qualifiers="const">
<return type="float" />
<param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<description>
+ Returns the minimum value range for the given parameter.
</description>
</method>
<method name="get_particle_flag" qualifiers="const">
@@ -63,6 +65,7 @@
<param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<param index="1" name="value" type="float" />
<description>
+ Sets the maximum value for the given parameter.
</description>
</method>
<method name="set_param_min">
@@ -70,6 +73,7 @@
<param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<param index="1" name="value" type="float" />
<description>
+ Sets the minimum value for the given parameter.
</description>
</method>
<method name="set_particle_flag">
@@ -89,29 +93,38 @@
Each particle's rotation will be animated along this [Curve].
</member>
<member name="angle_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum initial rotation applied to each particle, in degrees.
</member>
<member name="angle_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member angle_max].
</member>
<member name="angular_velocity_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
Each particle's angular velocity will vary along this [Curve].
</member>
<member name="angular_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum initial angular velocity (rotation speed) applied to each particle in [i]degrees[/i] per second.
</member>
<member name="angular_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member angular_velocity_max].
</member>
<member name="anim_offset_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
Each particle's animation offset will vary along this [Curve].
</member>
<member name="anim_offset_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum animation offset that corresponds to frame index in the texture. [code]0[/code] is the first frame, [code]1[/code] is the last one. See [member CanvasItemMaterial.particles_animation].
</member>
<member name="anim_offset_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member anim_offset_max].
</member>
<member name="anim_speed_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
Each particle's animation speed will vary along this [Curve].
</member>
<member name="anim_speed_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum particle animation speed. Animation speed of [code]1[/code] means that the particles will make full [code]0[/code] to [code]1[/code] offset cycle during lifetime, [code]2[/code] means [code]2[/code] cycles etc.
+ With animation speed greater than [code]1[/code], remember to enable [member CanvasItemMaterial.particles_anim_loop] property if you want the animation to repeat.
</member>
<member name="anim_speed_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member anim_speed_max].
</member>
<member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)">
Each particle's initial color. If [member texture] is defined, it will be multiplied by this color.
@@ -126,8 +139,10 @@
Damping will vary along this [Curve].
</member>
<member name="damping_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ The maximum rate at which particles lose velocity. For example value of [code]100[/code] means that the particle will go from [code]100[/code] velocity to [code]0[/code] in [code]1[/code] second.
</member>
<member name="damping_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member damping_max].
</member>
<member name="direction" type="Vector2" setter="set_direction" getter="get_direction" default="Vector2(1, 0)">
Unit vector specifying the particles' emission direction.
@@ -160,7 +175,7 @@
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
</member>
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
- The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
+ The particle system's frame rate is fixed to a value. For example, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
@@ -172,12 +187,16 @@
Each particle's hue will vary along this [Curve].
</member>
<member name="hue_variation_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum initial hue variation applied to each particle. It will shift the particle color's hue.
</member>
<member name="hue_variation_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member hue_variation_max].
</member>
<member name="initial_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum initial velocity magnitude for each particle. Direction comes from [member direction] and [member spread].
</member>
<member name="initial_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member initial_velocity_max].
</member>
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
Amount of time each particle will exist.
@@ -189,8 +208,10 @@
Each particle's linear acceleration will vary along this [Curve].
</member>
<member name="linear_accel_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum linear acceleration applied to each particle in the direction of motion.
</member>
<member name="linear_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member linear_accel_max].
</member>
<member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [CPUParticles2D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [CPUParticles2D] node (and its parents) when it is moved or rotated.
@@ -202,8 +223,10 @@
Each particle's orbital velocity will vary along this [Curve].
</member>
<member name="orbit_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum orbital velocity applied to each particle. Makes the particles circle around origin. Specified in number of full rotations around origin per second.
</member>
<member name="orbit_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member orbit_velocity_max].
</member>
<member name="particle_flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
Align Y axis of particle with the direction of its velocity.
@@ -215,8 +238,10 @@
Each particle's radial acceleration will vary along this [Curve].
</member>
<member name="radial_accel_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum radial acceleration applied to each particle. Makes particle accelerate away from the origin or towards it if negative.
</member>
<member name="radial_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member radial_accel_max].
</member>
<member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
Emission lifetime randomness ratio.
@@ -225,17 +250,24 @@
Each particle's scale will vary along this [Curve].
</member>
<member name="scale_amount_max" type="float" setter="set_param_max" getter="get_param_max" default="1.0">
+ Maximum initial scale applied to each particle.
</member>
<member name="scale_amount_min" type="float" setter="set_param_min" getter="get_param_min" default="1.0">
+ Minimum equivalent of [member scale_amount_max].
</member>
<member name="scale_curve_x" type="Curve" setter="set_scale_curve_x" getter="get_scale_curve_x">
+ Each particle's horizontal scale will vary along this [Curve].
+ [member split_scale] must be enabled.
</member>
<member name="scale_curve_y" type="Curve" setter="set_scale_curve_y" getter="get_scale_curve_y">
+ Each particle's vertical scale will vary along this [Curve].
+ [member split_scale] must be enabled.
</member>
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
Particle system's running speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
</member>
<member name="split_scale" type="bool" setter="set_split_scale" getter="get_split_scale" default="false">
+ If [code]true[/code], the scale curve will be split into x and y components. See [member scale_curve_x] and [member scale_curve_y].
</member>
<member name="spread" type="float" setter="set_spread" getter="get_spread" default="45.0">
Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees.
@@ -244,8 +276,10 @@
Each particle's tangential acceleration will vary along this [Curve].
</member>
<member name="tangential_accel_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum tangential acceleration applied to each particle. Tangential acceleration is perpendicular to the particle's velocity giving the particles a swirling motion.
</member>
<member name="tangential_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member tangential_accel_max].
</member>
<member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
Particle texture. If [code]null[/code], particles will be squares.
diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml
index 6b39c08b3f..3a15a117f5 100644
--- a/doc/classes/CPUParticles3D.xml
+++ b/doc/classes/CPUParticles3D.xml
@@ -28,12 +28,14 @@
<return type="float" />
<param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<description>
+ Returns the maximum value range for the given parameter.
</description>
</method>
<method name="get_param_min" qualifiers="const">
<return type="float" />
<param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<description>
+ Returns the minimum value range for the given parameter.
</description>
</method>
<method name="get_particle_flag" qualifiers="const">
@@ -62,7 +64,7 @@
<param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<param index="1" name="value" type="float" />
<description>
- Sets the maximum value for the given parameter
+ Sets the maximum value for the given parameter.
</description>
</method>
<method name="set_param_min">
@@ -70,7 +72,7 @@
<param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<param index="1" name="value" type="float" />
<description>
- Sets the minimum value for the given parameter
+ Sets the minimum value for the given parameter.
</description>
</method>
<method name="set_particle_flag">
@@ -187,7 +189,7 @@
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
</member>
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
- The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the particle system itself.
+ The particle system's frame rate is fixed to a value. For example, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the particle system itself.
</member>
<member name="flatness" type="float" setter="set_flatness" getter="get_flatness" default="0.0">
Amount of [member spread] in Y/Z plane. A value of [code]1[/code] restricts particles to X/Z plane.
diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml
index 2ffe880971..699e872e99 100644
--- a/doc/classes/CheckBox.xml
+++ b/doc/classes/CheckBox.xml
@@ -4,7 +4,7 @@
Binary choice user interface widget. See also [CheckButton].
</brief_description>
<description>
- A checkbox allows the user to make a binary choice (choosing only one of two possible options). It's similar to [CheckButton] in functionality, but it has a different appearance. To follow established UX patterns, it's recommended to use CheckBox when toggling it has [b]no[/b] immediate effect on something. For instance, it should be used when toggling it will only do something once a confirmation button is pressed.
+ A checkbox allows the user to make a binary choice (choosing only one of two possible options). It's similar to [CheckButton] in functionality, but it has a different appearance. To follow established UX patterns, it's recommended to use CheckBox when toggling it has [b]no[/b] immediate effect on something. For example, it could be used when toggling it will only do something once a confirmation button is pressed.
See also [BaseButton] which contains common properties and methods associated with this node.
</description>
<tutorials>
diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml
index 2f584103be..dfbaa7cbee 100644
--- a/doc/classes/CheckButton.xml
+++ b/doc/classes/CheckButton.xml
@@ -4,7 +4,7 @@
Checkable button. See also [CheckBox].
</brief_description>
<description>
- CheckButton is a toggle button displayed as a check field. It's similar to [CheckBox] in functionality, but it has a different appearance. To follow established UX patterns, it's recommended to use CheckButton when toggling it has an [b]immediate[/b] effect on something. For instance, it should be used if toggling it enables/disables a setting without requiring the user to press a confirmation button.
+ CheckButton is a toggle button displayed as a check field. It's similar to [CheckBox] in functionality, but it has a different appearance. To follow established UX patterns, it's recommended to use CheckButton when toggling it has an [b]immediate[/b] effect on something. For example, it could be used if toggling it enables/disables a setting without requiring the user to press a confirmation button.
See also [BaseButton] which contains common properties and methods associated with this node.
</description>
<tutorials>
diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml
index 58a536406f..5d3c6210f6 100644
--- a/doc/classes/ClassDB.xml
+++ b/doc/classes/ClassDB.xml
@@ -13,7 +13,7 @@
<return type="bool" />
<param index="0" name="class" type="StringName" />
<description>
- Returns [code]true[/code] if you can instance objects from the specified [param class], [code]false[/code] in other case.
+ Returns [code]true[/code] if objects can be instantiated from the specified [param class], otherwise returns [code]false[/code].
</description>
</method>
<method name="class_exists" qualifiers="const">
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 3a3803c1da..a11d7157f1 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -145,6 +145,11 @@
<return type="int" />
<param index="0" name="name" type="String" />
<description>
+ Returns the index of a named color. Use [method get_named_color] to get the actual color.
+ [codeblock]
+ var idx = Color.find_named_color("khaki")
+ modulate = Color.get_named_color(idx)
+ [/codeblock]
</description>
</method>
<method name="from_hsv" qualifiers="static">
@@ -187,6 +192,7 @@
<return type="Color" />
<param index="0" name="rgbe" type="int" />
<description>
+ Encodes a [Color] from a RGBE9995 format integer. See [constant Image.FORMAT_RGBE9995].
</description>
</method>
<method name="from_string" qualifiers="static">
@@ -194,6 +200,7 @@
<param index="0" name="str" type="String" />
<param index="1" name="default" type="Color" />
<description>
+ Creates a [Color] from string, which can be either a HTML color code or a named color. Fallbacks to [param default] if the string does not denote any valid color.
</description>
</method>
<method name="get_luminance" qualifiers="const">
@@ -208,29 +215,37 @@
<return type="Color" />
<param index="0" name="idx" type="int" />
<description>
+ Returns a named color with the given index. You can get the index from [method find_named_color] or iteratively from [method get_named_color_count].
</description>
</method>
<method name="get_named_color_count" qualifiers="static">
<return type="int" />
<description>
+ Returns the number of available named colors.
</description>
</method>
<method name="get_named_color_name" qualifiers="static">
<return type="String" />
<param index="0" name="idx" type="int" />
<description>
+ Returns the name of a color with the given index. You can get the index from [method find_named_color] or iteratively from [method get_named_color_count].
</description>
</method>
<method name="hex" qualifiers="static">
<return type="Color" />
<param index="0" name="hex" type="int" />
<description>
+ Returns the [Color] associated with the provided integer number, with 8 bits per channel in ARGB order. The integer should be 32-bit. Best used with hexadecimal notation.
+ [codeblock]
+ modulate = Color.hex(0xffff0000) # red
+ [/codeblock]
</description>
</method>
<method name="hex64" qualifiers="static">
<return type="Color" />
<param index="0" name="hex" type="int" />
<description>
+ Same as [method hex], but takes 64-bit integer and the color uses 16 bits per channel.
</description>
</method>
<method name="html" qualifiers="static">
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index d09b7f003e..cd1d0b016d 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -131,6 +131,7 @@
The width of the hue selection slider.
</theme_item>
<theme_item name="label_width" data_type="constant" type="int" default="10">
+ The minimum width of the color labels next to sliders.
</theme_item>
<theme_item name="margin" data_type="constant" type="int" default="4">
The margin around the [ColorPicker].
@@ -160,8 +161,10 @@
The indicator used to signalize that the color value is outside the 0-1 range.
</theme_item>
<theme_item name="picker_cursor" data_type="icon" type="Texture2D">
+ The image displayed over the color box/circle (depending on the [member picker_shape]), marking the currently selected color.
</theme_item>
<theme_item name="sample_bg" data_type="icon" type="Texture2D">
+ Background panel for the color preview box (visible when the color is translucent).
</theme_item>
<theme_item name="screen_picker" data_type="icon" type="Texture2D">
The icon for the screen color picker button.
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 7968b03c4b..91e9b65a8a 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -383,7 +383,7 @@
<method name="get_global_rect" qualifiers="const">
<return type="Rect2" />
<description>
- Returns the position and size of the control relative to the top-left corner of the screen. See [member position] and [member size].
+ Returns the position and size of the control relative to the [CanvasLayer]. See [member global_position] and [member size].
</description>
</method>
<method name="get_minimum_size" qualifiers="const">
@@ -972,7 +972,7 @@
<member name="clip_contents" type="bool" setter="set_clip_contents" getter="is_clipping_contents" default="false">
Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered and won't receive input.
</member>
- <member name="custom_minimum_size" type="Vector2i" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2i(0, 0)">
+ <member name="custom_minimum_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2(0, 0)">
The minimum size of the node's bounding rectangle. If you set it to a value greater than (0, 0), the node's bounding rectangle will always have at least this size, even if its content is smaller. If it's set to (0, 0), the node sizes automatically to fit its content, be it a texture or child nodes.
</member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0">
@@ -999,7 +999,7 @@
If this property is not set, Godot will select a "best guess" based on surrounding nodes in the scene tree.
</member>
<member name="global_position" type="Vector2" setter="_set_global_position" getter="get_global_position">
- The node's global position, relative to the world (usually to the top-left corner of the window).
+ The node's global position, relative to the world (usually to the [CanvasLayer]).
</member>
<member name="grow_horizontal" type="int" setter="set_h_grow_direction" getter="get_h_grow_direction" enum="Control.GrowDirection" default="1">
Controls the direction on the horizontal axis in which the control should grow if its horizontal minimum size is changed to be greater than its current size, as the control always has to be at least the minimum size.
diff --git a/doc/classes/CylinderShape3D.xml b/doc/classes/CylinderShape3D.xml
index 6ff142da59..dcb14ec945 100644
--- a/doc/classes/CylinderShape3D.xml
+++ b/doc/classes/CylinderShape3D.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Cylinder shape for collisions. Like [CapsuleShape3D], but without hemispheres at the cylinder's ends.
+ [b]Note:[/b] There are several known bugs with cylinder collision shapes. Using [CapsuleShape3D] or [BoxShape3D] instead is recommended.
[b]Performance:[/b] Being a primitive collision shape, [CylinderShape3D] is fast to check collisions against (though not as fast as [SphereShape3D]). [CylinderShape3D] is also more demanding compared to [CapsuleShape3D].
</description>
<tutorials>
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index a86aff060d..ac1f63af56 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -325,18 +325,21 @@
<return type="bool" />
<param index="0" name="right" type="Dictionary" />
<description>
+ Returns [code]true[/code] if the dictionaries differ, i.e. their key or value lists are different (including the order).
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
<param index="0" name="right" type="Dictionary" />
<description>
+ Returns [code]true[/code] if both dictionaries have the same contents, i.e. their keys list and value list are equal.
</description>
</operator>
<operator name="operator []">
<return type="Variant" />
<param index="0" name="key" type="Variant" />
<description>
+ Retunrs a value at the given [param key] or [code]null[/code] and error if the key does not exist. For safe access, use [method get] or [method has].
</description>
</operator>
</operators>
diff --git a/doc/classes/EditorFileDialog.xml b/doc/classes/EditorFileDialog.xml
index 891c8d7d92..51e3706981 100644
--- a/doc/classes/EditorFileDialog.xml
+++ b/doc/classes/EditorFileDialog.xml
@@ -4,6 +4,7 @@
A modified version of [FileDialog] used by the editor.
</brief_description>
<description>
+ [EditorFileDialog] is an enhanced version of [FileDialog] avaiable only to editor plugins. Additional features include list of favorited/recent files and ability to see files as thumbnails grid instead of list.
</description>
<tutorials>
</tutorials>
@@ -62,7 +63,7 @@
The dialog's open or save mode, which affects the selection behavior. See [enum FileMode]
</member>
<member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files" default="false">
- If [code]true[/code], hidden files and directories will be visible in the [EditorFileDialog].
+ If [code]true[/code], hidden files and directories will be visible in the [EditorFileDialog]. This property is synchronized with [member EditorSettings.filesystem/file_dialog/show_hidden_files].
</member>
<member name="title" type="String" setter="set_title" getter="get_title" overrides="Window" default="&quot;Save a File&quot;" />
</members>
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index 1e3b1f07ee..0beb2459a3 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -70,6 +70,7 @@
<method name="get_editor_paths">
<return type="EditorPaths" />
<description>
+ Returns the [EditorPaths] singleton.
</description>
</method>
<method name="get_editor_scale" qualifiers="const">
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 563987e2a3..e413c526f4 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -691,11 +691,13 @@
</signal>
<signal name="project_settings_changed">
<description>
+ Emitted when any project setting has changed.
</description>
</signal>
<signal name="resource_saved">
<param index="0" name="resource" type="Resource" />
<description>
+ Emitted when the given [param resource] was saved on disc.
</description>
</signal>
<signal name="scene_changed">
diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml
index 9170c449bf..2aca19510b 100644
--- a/doc/classes/EditorProperty.xml
+++ b/doc/classes/EditorProperty.xml
@@ -61,6 +61,7 @@
<method name="update_property">
<return type="void" />
<description>
+ Forces refresh of the property display.
</description>
</method>
</methods>
diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml
index dfc04c9cde..a02fd215d8 100644
--- a/doc/classes/EditorScript.xml
+++ b/doc/classes/EditorScript.xml
@@ -30,6 +30,7 @@
[/csharp]
[/codeblocks]
[b]Note:[/b] The script is run in the Editor context, which means the output is visible in the console window started with the Editor (stdout) instead of the usual Godot [b]Output[/b] dock.
+ [b]Note:[/b] EditorScript is [RefCounted], meaning it is destroyed when nothing references it. This can cause errors during asynchronous operations if there are no references to the script.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 68de08f094..818dda59bc 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -363,7 +363,7 @@
The color to use for the selection box that surrounds selected nodes in the 3D editor viewport. The color's alpha channel influences the selection box's opacity.
</member>
<member name="editors/3d_gizmos/gizmo_colors/instantiated" type="Color" setter="" getter="">
- The color override to use for 3D editor gizmos if the [Node3D] in question is part of an instanced scene file (from the perspective of the current scene).
+ The color override to use for 3D editor gizmos if the [Node3D] in question is part of an instantiated scene file (from the perspective of the current scene).
</member>
<member name="editors/3d_gizmos/gizmo_colors/joint" type="Color" setter="" getter="">
The 3D editor gizmo color for [Joint3D]s and [PhysicalBone3D]s.
@@ -677,19 +677,19 @@
If [code]true[/code], displays line length guidelines to help you keep line lengths in check. See also [member text_editor/appearance/guidelines/line_length_guideline_soft_column] and [member text_editor/appearance/guidelines/line_length_guideline_hard_column].
</member>
<member name="text_editor/appearance/gutters/highlight_type_safe_lines" type="bool" setter="" getter="">
- If [code]true[/code], highlights type-safe lines by displaying their line number color with [member text_editor/theme/highlighting/safe_line_number_color] instead of [member text_editor/theme/highlighting/line_number_color]. Type-safe lines are lines of code where the type of all variables is known at compile-time. These type-safe lines will run faster in Godot 4.0 and later thanks to typed instructions.
+ If [code]true[/code], highlights type-safe lines by displaying their line number color with [member text_editor/theme/highlighting/safe_line_number_color] instead of [member text_editor/theme/highlighting/line_number_color]. Type-safe lines are lines of code where the type of all variables is known at compile-time. These type-safe lines may run faster thanks to typed instructions.
</member>
<member name="text_editor/appearance/gutters/line_numbers_zero_padded" type="bool" setter="" getter="">
If [code]true[/code], displays line numbers with zero padding (e.g. [code]007[/code] instead of [code]7[/code]).
</member>
<member name="text_editor/appearance/gutters/show_bookmark_gutter" type="bool" setter="" getter="">
- If [code]true[/code], displays a gutter at the left containing icons for bookmarks.
+ If [code]true[/code], displays icons for bookmarks in a gutter at the left. Bookmarks remain functional when this setting is disabled.
</member>
<member name="text_editor/appearance/gutters/show_info_gutter" type="bool" setter="" getter="">
If [code]true[/code], displays a gutter at the left containing icons for methods with signal connections.
</member>
<member name="text_editor/appearance/gutters/show_line_numbers" type="bool" setter="" getter="">
- If [code]true[/code], displays line numbers in the gutter at the left.
+ If [code]true[/code], displays line numbers in a gutter at the left.
</member>
<member name="text_editor/appearance/lines/code_folding" type="bool" setter="" getter="">
If [code]true[/code], displays the folding arrows next to indented code sections and allows code folding. If [code]false[/code], hides the folding arrows next to indented code sections and disallows code folding.
@@ -758,7 +758,7 @@
[b]Note:[/b] You can hold down [kbd]Alt[/kbd] while using the mouse wheel to temporarily scroll 5 times faster.
</member>
<member name="text_editor/completion/add_type_hints" type="bool" setter="" getter="">
- If [code]true[/code], adds static typing hints such as [code]-&gt; void[/code] and [code]: int[/code] when performing method definition autocompletion.
+ If [code]true[/code], adds static typing hints such as [code]-&gt; void[/code] and [code]: int[/code] when using code autocompletion or when creating onready variables by drag and dropping nodes into the script editor while pressing the [kbd]Ctrl[/kbd] key.
</member>
<member name="text_editor/completion/auto_brace_complete" type="bool" setter="" getter="">
If [code]true[/code], automatically completes braces when making use of code completion.
@@ -809,7 +809,7 @@
The script editor's background color. If set to a translucent color, the editor theme's base color will be visible behind.
</member>
<member name="text_editor/theme/highlighting/base_type_color" type="Color" setter="" getter="">
- The script editor's base type color (used for types like [Vector2], [Vector3], ...).
+ The script editor's base type color (used for types like [Vector2], [Vector3], [Color], ...).
</member>
<member name="text_editor/theme/highlighting/bookmark_color" type="Color" setter="" getter="">
The script editor's bookmark icon color (displayed in the gutter).
@@ -869,10 +869,10 @@
[b]Note:[/b] When using the GDScript syntax highlighter, this is replaced by the function definition color configured in the syntax theme for function definitions (e.g. [code]func _ready():[/code]).
</member>
<member name="text_editor/theme/highlighting/keyword_color" type="Color" setter="" getter="">
- The script editor's non-control flow keyword color (used for keywords like [code]var[/code], [code]func[/code], some built-in methods, ...).
+ The script editor's non-control flow keyword color (used for keywords like [code]var[/code], [code]func[/code], [code]extends[/code], ...).
</member>
<member name="text_editor/theme/highlighting/line_length_guideline_color" type="Color" setter="" getter="">
- The script editor's color for the line length guideline. The "hard" line length guideline will be drawn with this color, whereas the "soft" line length guideline will be drawn with an opacity twice as low.
+ The script editor's color for the line length guideline. The "hard" line length guideline will be drawn with this color, whereas the "soft" line length guideline will be drawn with half of its opacity.
</member>
<member name="text_editor/theme/highlighting/line_number_color" type="Color" setter="" getter="">
The script editor's color for line numbers. See also [member text_editor/theme/highlighting/safe_line_number_color].
@@ -913,7 +913,7 @@
The script editor's background color for text. This should be set to a translucent color so that it can display on top of other line color modifiers such as [member text_editor/theme/highlighting/current_line_color].
</member>
<member name="text_editor/theme/highlighting/user_type_color" type="Color" setter="" getter="">
- The script editor's color for user-defined types (using [code]@class_name[/code]).
+ The script editor's color for user-defined types (using [code]class_name[/code]).
</member>
<member name="text_editor/theme/highlighting/word_highlighted_color" type="Color" setter="" getter="">
The script editor's color for words highlighted by selecting them. Only visible if [member text_editor/appearance/caret/highlight_all_occurrences] is [code]true[/code].
diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml
index 2ada211dab..9961e11f7d 100644
--- a/doc/classes/EditorSpinSlider.xml
+++ b/doc/classes/EditorSpinSlider.xml
@@ -10,13 +10,16 @@
</tutorials>
<members>
<member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false">
+ If [code]true[/code], the slider will not draw background.
</member>
<member name="hide_slider" type="bool" setter="set_hide_slider" getter="is_hiding_slider" default="false">
If [code]true[/code], the slider is hidden.
</member>
<member name="label" type="String" setter="set_label" getter="get_label" default="&quot;&quot;">
+ The text that displays to the left of the value.
</member>
<member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false">
+ If [code]true[/code], the slider can't be interacted with.
</member>
<member name="suffix" type="String" setter="set_suffix" getter="get_suffix" default="&quot;&quot;">
The suffix to display after the value (in a faded color). This should generally be a plural word. You may have to use an abbreviation if the suffix is too long to be displayed.
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index 2b8663e039..821fae37a6 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -146,11 +146,13 @@
<return type="ScriptLanguage" />
<param index="0" name="index" type="int" />
<description>
+ Returns an instance of a [ScriptLanguage] with the given index.
</description>
</method>
<method name="get_script_language_count">
<return type="int" />
<description>
+ Returns the number of available script languages. Use with [method get_script_language].
</description>
</method>
<method name="get_singleton" qualifiers="const">
@@ -163,6 +165,7 @@
<method name="get_singleton_list" qualifiers="const">
<return type="PackedStringArray" />
<description>
+ Returns a list of available global singletons.
</description>
</method>
<method name="get_version_info" qualifiers="const">
@@ -244,6 +247,7 @@
<return type="void" />
<param index="0" name="language" type="ScriptLanguage" />
<description>
+ Registers a [ScriptLanguage] instance to be available with [code]ScriptServer[/code].
</description>
</method>
<method name="register_singleton">
@@ -251,12 +255,14 @@
<param index="0" name="name" type="StringName" />
<param index="1" name="instance" type="Object" />
<description>
+ Registers the given object as a singleton, globally available under [param name].
</description>
</method>
<method name="unregister_singleton">
<return type="void" />
<param index="0" name="name" type="StringName" />
<description>
+ Unregisters the singleton registered under [param name]. The singleton object is not freed. Only works with user-defined singletons created with [method register_singleton].
</description>
</method>
</methods>
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index f41e34c43a..043c08eed5 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -52,7 +52,7 @@
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
</member>
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="30">
- The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
+ The particle system's frame rate is fixed to a value. For example, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index e7b436010e..d0be4d784a 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -84,7 +84,7 @@
Time ratio between each emission. If [code]0[/code], particles are emitted continuously. If [code]1[/code], all particles are emitted simultaneously.
</member>
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="30">
- The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
+ The particle system's frame rate is fixed to a value. For example, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index eb5b3dad91..88cea6820e 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -26,7 +26,7 @@
<param index="1" name="src_rect" type="Rect2i" />
<param index="2" name="dst" type="Vector2i" />
<description>
- Alpha-blends [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with not positive size is treated as empty.
+ Alpha-blends [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with non-positive size is treated as empty.
</description>
</method>
<method name="blend_rect_mask">
@@ -36,7 +36,7 @@
<param index="2" name="src_rect" type="Rect2i" />
<param index="3" name="dst" type="Vector2i" />
<description>
- Alpha-blends [param src_rect] from [param src] image to this image using [param mask] image at coordinates [param dst], clipped accordingly to both image bounds. Alpha channels are required for both [param src] and [param mask]. [param dst] pixels and [param src] pixels will blend if the corresponding mask pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with not positive size is treated as empty.
+ Alpha-blends [param src_rect] from [param src] image to this image using [param mask] image at coordinates [param dst], clipped accordingly to both image bounds. Alpha channels are required for both [param src] and [param mask]. [param dst] pixels and [param src] pixels will blend if the corresponding mask pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with non-positive size is treated as empty.
</description>
</method>
<method name="blit_rect">
@@ -45,7 +45,7 @@
<param index="1" name="src_rect" type="Rect2i" />
<param index="2" name="dst" type="Vector2i" />
<description>
- Copies [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with not positive size is treated as empty.
+ Copies [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with non-positive size is treated as empty.
</description>
</method>
<method name="blit_rect_mask">
@@ -55,7 +55,7 @@
<param index="2" name="src_rect" type="Rect2i" />
<param index="3" name="dst" type="Vector2i" />
<description>
- Blits [param src_rect] area from [param src] image to this image at the coordinates given by [param dst], clipped accordingly to both image bounds. [param src] pixel is copied onto [param dst] if the corresponding [param mask] pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with not positive size is treated as empty.
+ Blits [param src_rect] area from [param src] image to this image at the coordinates given by [param dst], clipped accordingly to both image bounds. [param src] pixel is copied onto [param dst] if the corresponding [param mask] pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with non-positive size is treated as empty.
</description>
</method>
<method name="bump_map_to_normal_map">
diff --git a/doc/classes/InputEventScreenTouch.xml b/doc/classes/InputEventScreenTouch.xml
index fb50454917..346b6bf732 100644
--- a/doc/classes/InputEventScreenTouch.xml
+++ b/doc/classes/InputEventScreenTouch.xml
@@ -11,6 +11,9 @@
<link title="InputEvent">$DOCS_URL/tutorials/inputs/inputevent.html</link>
</tutorials>
<members>
+ <member name="double_tap" type="bool" setter="set_double_tap" getter="is_double_tap" default="false">
+ If [code]true[/code], the touch's state is a double tap.
+ </member>
<member name="index" type="int" setter="set_index" getter="get_index" default="0">
The touch index in the case of a multi-touch event. One index = one finger.
</member>
diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml
index d3d5a7bfaa..facbe5fd0f 100644
--- a/doc/classes/Mesh.xml
+++ b/doc/classes/Mesh.xml
@@ -129,7 +129,7 @@
<method name="get_aabb" qualifiers="const">
<return type="AABB" />
<description>
- Returns the smallest [AABB] enclosing this mesh in local space. Not affected by [code]custom_aabb[/code]. See also [method VisualInstance3D.get_transformed_aabb].
+ Returns the smallest [AABB] enclosing this mesh in local space. Not affected by [code]custom_aabb[/code].
[b]Note:[/b] This is only implemented for [ArrayMesh] and [PrimitiveMesh].
</description>
</method>
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index ce2b5f2584..d8a232b3cf 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -19,7 +19,7 @@
<method name="get_aabb" qualifiers="const">
<return type="AABB" />
<description>
- Returns the visibility axis-aligned bounding box in local space. See also [method VisualInstance3D.get_transformed_aabb].
+ Returns the visibility axis-aligned bounding box in local space.
</description>
</method>
<method name="get_instance_color" qualifiers="const">
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index 9db100c9f8..022b4826ea 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -4,7 +4,7 @@
Pre-parsed scene tree path.
</brief_description>
<description>
- A pre-parsed relative or absolute path in a scene tree, for use with [method Node.get_node] and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For instance, [code]"Path2D/PathFollow2D/Sprite2D:texture:size"[/code] would refer to the [code]size[/code] property of the [code]texture[/code] resource on the node named [code]"Sprite2D"[/code] which is a child of the other named nodes in the path.
+ A pre-parsed relative or absolute path in a scene tree, for use with [method Node.get_node] and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For example, [code]"Path2D/PathFollow2D/Sprite2D:texture:size"[/code] would refer to the [code]size[/code] property of the [code]texture[/code] resource on the node named [code]"Sprite2D"[/code] which is a child of the other named nodes in the path.
You will usually just pass a string to [method Node.get_node] and it will be automatically converted, but you may occasionally want to parse a path ahead of time with [NodePath] or the literal syntax [code]^"path"[/code]. Exporting a [NodePath] variable will give you a node selection widget in the properties panel of the editor, which can often be useful.
A [NodePath] is composed of a list of slash-separated node names (like a filesystem path) and an optional colon-separated list of "subnames" which can be resources or properties.
Some examples of NodePaths include the following:
diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml
index 807a94ab24..d4050e3bd1 100644
--- a/doc/classes/ParticleProcessMaterial.xml
+++ b/doc/classes/ParticleProcessMaterial.xml
@@ -217,7 +217,7 @@
Maximum linear acceleration applied to each particle in the direction of motion.
</member>
<member name="linear_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
- Minimum equivalent of [member linear_accel_min].
+ Minimum equivalent of [member linear_accel_max].
</member>
<member name="orbit_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
Each particle's orbital velocity will vary along this [CurveTexture].
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 23287f4de1..c99760996f 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -533,6 +533,8 @@
<param index="0" name="id" type="int" />
<description>
Emitted when an item of some [param id] is pressed or its accelerator is activated.
+
+ [b]Note:[/b] If [param id] is negative (either explicitly or due to overflow), this will return the correponding index instead.
</description>
</signal>
<signal name="index_pressed">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index ff66affeab..a8080c70c6 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -568,6 +568,13 @@
<member name="display/window/ios/hide_home_indicator" type="bool" setter="" getter="" default="true">
If [code]true[/code], the home indicator is hidden automatically. This only affects iOS devices without a physical home button.
</member>
+ <member name="display/window/ios/hide_status_bar" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], the status bar is hidden while the app is running.
+ </member>
+ <member name="display/window/ios/suppress_ui_gesture" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], it will require two swipes to access iOS UI that uses gestures.
+ [b]Note:[/b] This setting has no effect on the home indicator if [code]hide_home_indicator[/code] is [code]true[/code].
+ </member>
<member name="display/window/per_pixel_transparency/allowed" type="bool" setter="" getter="" default="false">
If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it. See also [member display/window/size/transparent] and [member rendering/transparent_background].
</member>
diff --git a/doc/classes/Projection.xml b/doc/classes/Projection.xml
index 5690ea5e95..602833bca5 100644
--- a/doc/classes/Projection.xml
+++ b/doc/classes/Projection.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Projection" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ 3D projection (4x4 matrix).
</brief_description>
<description>
+ A 4x4 matrix used for 3D projective transformations. It can represent transformations such as translation, rotation, scaling, shearing, and perspective division. It consists of four [Vector4] columns.
+ For purely linear transformations (translation, rotation, and scale), it is recommended to use [Transform3D], as it is more performant and has a lower memory footprint.
+ Used internally as [Camera3D]'s projection matrix.
</description>
<tutorials>
</tutorials>
@@ -10,18 +14,21 @@
<constructor name="Projection">
<return type="Projection" />
<description>
+ Constructs a default-initialized [Projection] set to [constant IDENTITY].
</description>
</constructor>
<constructor name="Projection">
<return type="Projection" />
<param index="0" name="from" type="Projection" />
<description>
+ Constructs a [Projection] as a copy of the given [Projection].
</description>
</constructor>
<constructor name="Projection">
<return type="Projection" />
<param index="0" name="from" type="Transform3D" />
<description>
+ Constructs a Projection as a copy of the given [Transform3D].
</description>
</constructor>
<constructor name="Projection">
@@ -40,12 +47,14 @@
<return type="Projection" />
<param index="0" name="flip_y" type="bool" />
<description>
+ Creates a new [Projection] that projects positions from a depth range of [code]-1[/code] to [code]1[/code] to one that ranges from [code]0[/code] to [code]1[/code], and flips the projected positions vertically, according to [param flip_y].
</description>
</method>
<method name="create_fit_aabb" qualifiers="static">
<return type="Projection" />
<param index="0" name="aabb" type="AABB" />
<description>
+ Creates a new [Projection] that scales a given projection to fit around a given [AABB] in projection space.
</description>
</method>
<method name="create_for_hmd" qualifiers="static">
@@ -59,6 +68,8 @@
<param index="6" name="z_near" type="float" />
<param index="7" name="z_far" type="float" />
<description>
+ Creates a new [Projection] for projecting positions onto a head-mounted display with the given X:Y aspect ratio, distance between eyes, display width, distance to lens, oversampling factor, and depth clipping planes.
+ [param eye] creates the projection for the left eye when set to 1, or the right eye when set to 2.
</description>
</method>
<method name="create_frustum" qualifiers="static">
@@ -70,6 +81,7 @@
<param index="4" name="z_near" type="float" />
<param index="5" name="z_far" type="float" />
<description>
+ Creates a new [Projection] that projects positions in a frustum with the given clipping planes.
</description>
</method>
<method name="create_frustum_aspect" qualifiers="static">
@@ -81,12 +93,15 @@
<param index="4" name="z_far" type="float" />
<param index="5" name="flip_fov" type="bool" default="false" />
<description>
+ Creates a new [Projection] that projects positions in a frustum with the given size, X:Y aspect ratio, offset, and clipping planes.
+ [param flip_fov] determines whether the projection's field of view is flipped over its diagonal.
</description>
</method>
<method name="create_light_atlas_rect" qualifiers="static">
<return type="Projection" />
<param index="0" name="rect" type="Rect2" />
<description>
+ Creates a new [Projection] that projects positions into the given [Rect2].
</description>
</method>
<method name="create_orthogonal" qualifiers="static">
@@ -98,6 +113,7 @@
<param index="4" name="z_near" type="float" />
<param index="5" name="z_far" type="float" />
<description>
+ Creates a new [Projection] that projects positions using an orthogonal projection with the given clipping planes.
</description>
</method>
<method name="create_orthogonal_aspect" qualifiers="static">
@@ -108,6 +124,8 @@
<param index="3" name="z_far" type="float" />
<param index="4" name="flip_fov" type="bool" default="false" />
<description>
+ Creates a new [Projection] that projects positions using an orthogonal projection with the given size, X:Y aspect ratio, and clipping planes.
+ [param flip_fov] determines whether the projection's field of view is flipped over its diagonal.
</description>
</method>
<method name="create_perspective" qualifiers="static">
@@ -118,6 +136,8 @@
<param index="3" name="z_far" type="float" />
<param index="4" name="flip_fov" type="bool" default="false" />
<description>
+ Creates a new [Projection] that projects positions using a perspective projection with the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping planes.
+ [param flip_fov] determines whether the projection's field of view is flipped over its diagonal.
</description>
</method>
<method name="create_perspective_hmd" qualifiers="static">
@@ -131,31 +151,40 @@
<param index="6" name="intraocular_dist" type="float" />
<param index="7" name=" convergence_dist" type="float" />
<description>
+ Creates a new [Projection] that projects positions using a perspective projection with the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping distances. The projection is adjusted for a head-mounted display with the given distance between eyes and distance to a point that can be focused on.
+ [param eye] creates the projection for the left eye when set to 1, or the right eye when set to 2.
+ [param flip_fov] determines whether the projection's field of view is flipped over its diagonal.
</description>
</method>
<method name="determinant" qualifiers="const">
<return type="float" />
<description>
+ Returns a scalar value that is the signed factor by which areas are scaled by this matrix. If the sign is negative, the matrix flips the orientation of the area.
+ The determinant can be used to calculate the invertibility of a matrix or solve linear systems of equations involving the matrix, among other applications.
</description>
</method>
<method name="flipped_y" qualifiers="const">
<return type="Projection" />
<description>
+ Returns a copy of this [Projection] with the signs of the values of the Y column flipped.
</description>
</method>
<method name="get_aspect" qualifiers="const">
<return type="float" />
<description>
+ Returns the X:Y aspect ratio of this [Projection]'s viewport.
</description>
</method>
<method name="get_far_plane_half_extents" qualifiers="const">
<return type="Vector2" />
<description>
+ Returns the dimensions of the far clipping plane of the projection, divided by two.
</description>
</method>
<method name="get_fov" qualifiers="const">
<return type="float" />
<description>
+ Returns the horizontal field of view of the projection (in degrees).
</description>
</method>
<method name="get_fovy" qualifiers="static">
@@ -163,89 +192,114 @@
<param index="0" name="fovx" type="float" />
<param index="1" name="aspect" type="float" />
<description>
+ Returns the vertical field of view of the projection (in degrees) associated with the given horizontal field of view (in degrees) and aspect ratio.
</description>
</method>
<method name="get_lod_multiplier" qualifiers="const">
<return type="float" />
<description>
+ Returns the factor by which the visible level of detail is scaled by this [Projection].
</description>
</method>
<method name="get_pixels_per_meter" qualifiers="const">
<return type="int" />
<param index="0" name="for_pixel_width" type="int" />
<description>
+ Returns the number of pixels with the given pixel width displayed per meter, after this [Projection] is applied.
</description>
</method>
<method name="get_projection_plane" qualifiers="const">
<return type="Plane" />
<param index="0" name="plane" type="int" />
<description>
+ Returns the clipping plane of this [Projection] whose index is given by [param plane].
+ [param plane] should be equal to one of [constant PLANE_NEAR], [constant PLANE_FAR], [constant PLANE_LEFT], [constant PLANE_TOP], [constant PLANE_RIGHT], or [constant PLANE_BOTTOM].
</description>
</method>
<method name="get_viewport_half_extents" qualifiers="const">
<return type="Vector2" />
<description>
+ Returns the dimensions of the viewport plane that this [Projection] projects positions onto, divided by two.
</description>
</method>
<method name="get_z_far" qualifiers="const">
<return type="float" />
<description>
+ Returns the distance for this [Projection] beyond which positions are clipped.
</description>
</method>
<method name="get_z_near" qualifiers="const">
<return type="float" />
<description>
+ Returns the distance for this [Projection] before which positions are clipped.
</description>
</method>
<method name="inverse" qualifiers="const">
<return type="Projection" />
<description>
+ Returns a [Projection] that performs the inverse of this [Projection]'s projective transformation.
</description>
</method>
<method name="is_orthogonal" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if this [Projection] performs an orthogonal projection.
</description>
</method>
<method name="jitter_offseted" qualifiers="const">
<return type="Projection" />
<param index="0" name="offset" type="Vector2" />
<description>
+ Returns a [Projection] with the X and Y values from the given [Vector2] added to the first and second values of the final column respectively.
</description>
</method>
<method name="perspective_znear_adjusted" qualifiers="const">
<return type="Projection" />
<param index="0" name="new_znear" type="float" />
<description>
+ Returns a [Projection] with the near clipping distance adjusted to be [param new_znear].
+ [b]Note:[/b] The original [Projection] must be a perspective projection.
</description>
</method>
</methods>
<members>
<member name="w" type="Vector4" setter="" getter="" default="Vector4(0, 0, 0, 1)">
+ The projection matrix's W vector (column 3). Equivalent to array index [code]3[/code].
</member>
<member name="x" type="Vector4" setter="" getter="" default="Vector4(1, 0, 0, 0)">
+ The projection matrix's X vector (column 0). Equivalent to array index [code]0[/code].
</member>
<member name="y" type="Vector4" setter="" getter="" default="Vector4(0, 1, 0, 0)">
+ The projection matrix's Y vector (column 1). Equivalent to array index [code]1[/code].
</member>
<member name="z" type="Vector4" setter="" getter="" default="Vector4(0, 0, 1, 0)">
+ The projection matrix's Z vector (column 2). Equivalent to array index [code]2[/code].
</member>
</members>
<constants>
<constant name="PLANE_NEAR" value="0">
+ The index value of the projection's near clipping plane.
</constant>
<constant name="PLANE_FAR" value="1">
+ The index value of the projection's far clipping plane.
</constant>
<constant name="PLANE_LEFT" value="2">
+ The index value of the projection's left clipping plane.
</constant>
<constant name="PLANE_TOP" value="3">
+ The index value of the projection's top clipping plane.
</constant>
<constant name="PLANE_RIGHT" value="4">
+ The index value of the projection's right clipping plane.
</constant>
<constant name="PLANE_BOTTOM" value="5">
+ The index value of the projection bottom clipping plane.
</constant>
<constant name="IDENTITY" value="Projection(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)">
+ A [Projection] with no transformation defined. When applied to other data structures, no transformation is performed.
</constant>
<constant name="ZERO" value="Projection(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)">
+ A [Projection] with all values initialized to 0. When applied to other data structures, they will be zeroed.
</constant>
</constants>
<operators>
@@ -253,30 +307,38 @@
<return type="bool" />
<param index="0" name="right" type="Projection" />
<description>
+ Returns [code]true[/code] if the projections are not equal.
+ [b]Note:[/b] Due to floating-point precision errors, this may return [code]true[/code], even if the projections are virtually equal. An [code]is_equal_approx[/code] method may be added in a future version of Godot.
</description>
</operator>
<operator name="operator *">
<return type="Projection" />
<param index="0" name="right" type="Projection" />
<description>
+ Returns a [Projection] that applies the combined transformations of this [Projection] and [param right].
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
<param index="0" name="right" type="Vector4" />
<description>
+ Projects (multiplies) the given [Vector4] by this [Projection] matrix.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
<param index="0" name="right" type="Projection" />
<description>
+ Returns [code]true[/code] if the projections are equal.
+ [b]Note:[/b] Due to floating-point precision errors, this may return [code]false[/code], even if the projections are virtually equal. An [code]is_equal_approx[/code] method may be added in a future version of Godot.
</description>
</operator>
<operator name="operator []">
<return type="Vector4" />
<param index="0" name="index" type="int" />
<description>
+ Returns the column of the [Projection] with the given index.
+ Indices are in the following order: x, y, z, w.
</description>
</operator>
</operators>
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index 3adf10da2d..b2b8a37e39 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -4,7 +4,8 @@
Base class for all resources.
</brief_description>
<description>
- Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Since they inherit from [RefCounted], resources are reference-counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference-counted and can be instantiated from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource.
+ Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Since they inherit from [RefCounted], resources are reference-counted and freed when no longer in use. They can also be nested within other resources, and saved on disk. Once loaded from disk, further attempts to load a resource by [member resource_path] returns the same reference. [PackedScene], one of the most common [Object]s in a Godot project, is also a resource, uniquely capable of storing and instantiating the [Node]s it contains as many times as desired.
+ In GDScript, resources can loaded from disk by their [member resource_path] using [method @GDScript.load] or [method @GDScript.preload].
[b]Note:[/b] In C#, resources will not be freed instantly after they are no longer in use. Instead, garbage collection will run periodically and will free resources that are no longer in use. This means that unused resources will linger on for a while before being removed.
</description>
<tutorials>
@@ -15,77 +16,94 @@
<method name="_get_rid" qualifiers="virtual">
<return type="RID" />
<description>
+ Override this method to return a custom [RID] when [method get_rid] is called.
</description>
</method>
<method name="duplicate" qualifiers="const">
<return type="Resource" />
<param index="0" name="subresources" type="bool" default="false" />
<description>
- Duplicates the resource, returning a new resource with the exported members copied. [b]Note:[/b] To duplicate the resource the constructor is called without arguments. This method will error when the constructor doesn't have default values.
- By default, sub-resources are shared between resource copies for efficiency. This can be changed by passing [code]true[/code] to the [param subresources] argument which will copy the subresources.
- [b]Note:[/b] If [param subresources] is [code]true[/code], this method will only perform a shallow copy. Nested resources within subresources will not be duplicated and will still be shared.
- [b]Note:[/b] When duplicating a resource, only [code]export[/code]ed properties are copied. Other properties will be set to their default value in the new resource.
+ Duplicates this resource, returning a new resource with its [code]export[/code]ed or [constant PROPERTY_USAGE_STORAGE] properties copied from the original.
+ If [param subresources] is [code]false[/code], a shallow copy is returned. Nested resources within subresources are not duplicated and are shared from the original resource. This behavior can be overriden by the [constant PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE] flag.
+ [b]Note:[/b] For custom resources, this method will fail if [method Object._init] has been defined with required parameters.
</description>
</method>
<method name="emit_changed">
<return type="void" />
<description>
- Emits the [signal changed] signal.
- If external objects which depend on this resource should be updated, this method must be called manually whenever the state of this resource has changed (such as modification of properties).
- The method is equivalent to:
+ Emits the [signal changed] signal. This method is called automatically for built-in resources.
+ [b]Note:[/b] For custom resources, it's recommended to call this method whenever a meaningful change occurs, such as a modified property. This ensures that custom [Object]s depending on the resource are properly updated.
[codeblock]
- emit_signal("changed")
+ var damage:
+ set(new_value):
+ if damage != new_value:
+ damage = new_value
+ emit_changed()
[/codeblock]
- [b]Note:[/b] This method is called automatically for built-in resources.
</description>
</method>
<method name="get_local_scene" qualifiers="const">
<return type="Node" />
<description>
- If [member resource_local_to_scene] is enabled and the resource was loaded from a [PackedScene] instantiation, returns the local scene where this resource's unique copy is in use. Otherwise, returns [code]null[/code].
+ If [member resource_local_to_scene] is set to [code]true[/code] and the resource has been loaded from a [PackedScene] instantiation, returns the root [Node] of the scene where this resource is used. Otherwise, returns [code]null[/code].
</description>
</method>
<method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
- Returns the RID of the resource (or an empty RID). Many resources (such as [Texture2D], [Mesh], etc) are high-level abstractions of resources stored in a server, so this function will return the original RID.
+ Returns the [RID] of this resource (or an empty RID). Many resources (such as [Texture2D], [Mesh], and so on) are high-level abstractions of resources stored in a specialised server ([DisplayServer], [RenderingServer], etc.), so this function will return the original [RID].
</description>
</method>
<method name="setup_local_to_scene">
<return type="void" />
<description>
- This method is called when a resource with [member resource_local_to_scene] enabled is loaded from a [PackedScene] instantiation. Its behavior can be customized by connecting [signal setup_local_to_scene_requested] from script.
- For most resources, this method performs no base logic. [ViewportTexture] performs custom logic to properly set the proxy texture and flags in the local viewport.
+ Emits the [signal setup_local_to_scene_requested] signal. If [member resource_local_to_scene] is set to [code]true[/code], this method is called from [method PackedScene.instantiate] by the newly duplicated resource within the scene instance.
+ For most resources, this method performs no logic of its own. Custom behavior can be defined by connecting [signal setup_local_to_scene_requested] from a script, [b]not[/b] by overriding this method.
+ [b]Example:[/b] Assign a random value to [code]health[/code] for every duplicated Resource from an instantiated scene, excluding the original.
+ [codeblock]
+ extends Resource
+
+ var health = 0
+
+ func _init():
+ setup_local_to_scene_requested.connect(randomize_health)
+
+ func randomize_health():
+ health = randi_range(10, 40)
+ [/codeblock]
</description>
</method>
<method name="take_over_path">
<return type="void" />
<param index="0" name="path" type="String" />
<description>
- Sets the path of the resource, potentially overriding an existing cache entry for this path. This differs from setting [member resource_path], as the latter would error out if another resource was already cached for the given path.
+ Sets the [member resource_path] to [param path], potentially overriding an existing cache entry for this path. Further attempts to load an overridden resource by path will instead return this resource.
</description>
</method>
</methods>
<members>
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" default="false">
- If [code]true[/code], the resource will be made unique in each instance of its local scene. It can thus be modified in a scene instance without impacting other instances of that same scene.
+ If [code]true[/code], the resource is duplicated for each instance of all scenes using it. At run-time, the resource can be modified in one scene without affecting other instances (see [method PackedScene.instantiate]).
+ [b]Note:[/b] Changing this property at run-time has no effect on already created duplicate resources.
</member>
<member name="resource_name" type="String" setter="set_name" getter="get_name" default="&quot;&quot;">
- The name of the resource. This is an optional identifier. If [member resource_name] is not empty, its value will be displayed to represent the current resource in the editor inspector. For built-in scripts, the [member resource_name] will be displayed as the tab name in the script editor.
+ An optional name for this resource. When defined, its value is displayed to represent the resource in the Inspector dock. For built-in scripts, the name is displayed as part of the tab name in the script editor.
</member>
<member name="resource_path" type="String" setter="set_path" getter="get_path" default="&quot;&quot;">
- The path to the resource. In case it has its own file, it will return its filepath. If it's tied to the scene, it will return the scene's path, followed by the resource's index.
+ The unique path to this resource. If it has been saved to disk, the value will be its filepath. If the resource is exclusively contained within a scene, the value will be the [PackedScene]'s filepath, followed by an unique identifier.
+ [b]Note:[/b] Setting this property manually may fail if a resource with the same path has already been previously loaded. If necessary, use [method take_over_path].
</member>
</members>
<signals>
<signal name="changed">
<description>
- Emitted whenever the resource changes.
- [b]Note:[/b] This signal is not emitted automatically for custom resources, which means that you need to create a setter and emit the signal yourself.
+ Emitted when the resource changes, usually when one of its properties is modified. See also [method emit_changed].
+ [b]Note:[/b] This signal is not emitted automatically for properties of custom resources. If necessary, a setter needs to be created to emit the signal.
</description>
</signal>
<signal name="setup_local_to_scene_requested">
<description>
+ Emitted when [method setup_local_to_scene] is called, usually by a newly duplicated resource with [member resource_local_to_scene] set to [code]true[/code]. Custom behavior can be defined by connecting this signal.
</description>
</signal>
</signals>
diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml
index 40ec8ed429..b4b14c01c6 100644
--- a/doc/classes/Script.xml
+++ b/doc/classes/Script.xml
@@ -4,7 +4,7 @@
A class stored as a resource.
</brief_description>
<description>
- A class stored as a resource. A script extends the functionality of all objects that instance it.
+ A class stored as a resource. A script extends the functionality of all objects that instantiate it.
This is the base class for all scripts and should not be used directly. Trying to create a new script with this class will result in an error.
The [code]new[/code] method of a script subclass creates a new instance. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml
index 34ca228795..7be0ba64d6 100644
--- a/doc/classes/Shape2D.xml
+++ b/doc/classes/Shape2D.xml
@@ -66,6 +66,12 @@
Draws a solid shape onto a [CanvasItem] with the [RenderingServer] API filled with the specified [param color]. The exact drawing method is specific for each shape and cannot be configured.
</description>
</method>
+ <method name="get_rect" qualifiers="const">
+ <return type="Rect2" />
+ <description>
+ Returns a [Rect2] representing the shapes boundary.
+ </description>
+ </method>
</methods>
<members>
<member name="custom_solver_bias" type="float" setter="set_custom_solver_bias" getter="get_custom_solver_bias" default="0.0">
diff --git a/doc/classes/SkeletonProfile.xml b/doc/classes/SkeletonProfile.xml
index 55d21f3224..57bdd52d9e 100644
--- a/doc/classes/SkeletonProfile.xml
+++ b/doc/classes/SkeletonProfile.xml
@@ -7,6 +7,7 @@
This resource is used in [EditorScenePostImport]. Some parameters are referring to bones in [Skeleton3D], [Skin], [Animation], and some other nodes are rewritten based on the parameters of [SkeletonProfile].
</description>
<tutorials>
+ <link title="Retargeting 3D Skeletons">$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html</link>
</tutorials>
<methods>
<method name="find_bone" qualifiers="const">
diff --git a/doc/classes/SkeletonProfileHumanoid.xml b/doc/classes/SkeletonProfileHumanoid.xml
index 11f0521718..0dbd66d8d6 100644
--- a/doc/classes/SkeletonProfileHumanoid.xml
+++ b/doc/classes/SkeletonProfileHumanoid.xml
@@ -6,6 +6,7 @@
A [SkeletonProfile] as a preset that is optimized for the human form. This exists for standardization, so all parameters are read-only.
</description>
<tutorials>
+ <link title="Retargeting 3D Skeletons">$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html</link>
</tutorials>
<members>
<member name="bone_size" type="int" setter="set_bone_size" getter="get_bone_size" overrides="SkeletonProfile" default="56" />
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 316bb923b7..320b9fd737 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -364,7 +364,7 @@
<return type="bool" />
<param index="0" name="with_prefix" type="bool" default="false" />
<description>
- Returns [code]true[/code] if this string contains a valid hexadecimal number. If [param with_prefix] is [code]true[/code], then a validity of the hexadecimal number is determined by [code]0x[/code] prefix, for instance: [code]0xDEADC0DE[/code].
+ Returns [code]true[/code] if this string contains a valid hexadecimal number. If [param with_prefix] is [code]true[/code], then a validity of the hexadecimal number is determined by the [code]0x[/code] prefix, for example: [code]0xDEADC0DE[/code].
</description>
</method>
<method name="is_valid_html_color" qualifiers="const">
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index ccec691107..d56cc9a31b 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -133,6 +133,7 @@
<description>
Generates normals from vertices so you do not have to do it manually. If [param flip] is [code]true[/code], the resulting normals will be inverted. [method generate_normals] should be called [i]after[/i] generating geometry and [i]before[/i] committing the mesh using [method commit] or [method commit_to_arrays]. For correct display of normal-mapped surfaces, you will also have to generate tangents using [method generate_tangents].
[b]Note:[/b] [method generate_normals] only works if the primitive type to be set to [constant Mesh.PRIMITIVE_TRIANGLES].
+ [b]Note:[/b] [method generate_normals] takes smooth groups into account. If you don't specify any smooth group for each vertex, [method generate_normals] will smooth normals for you.
</description>
</method>
<method name="generate_tangents">
diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml
index 14e89a1b74..3dd8c339b2 100644
--- a/doc/classes/Texture2D.xml
+++ b/doc/classes/Texture2D.xml
@@ -33,7 +33,7 @@
</method>
<method name="_draw_rect_region" qualifiers="virtual const">
<return type="void" />
- <param index="0" name="tp_canvas_item" type="RID" />
+ <param index="0" name="to_canvas_item" type="RID" />
<param index="1" name="rect" type="Rect2" />
<param index="2" name="src_rect" type="Rect2" />
<param index="3" name="modulate" type="Color" />
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 348184a16a..01246f0c2e 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -365,7 +365,7 @@
Show or hide the TileMap's collision shapes. If set to [constant VISIBILITY_MODE_DEFAULT], this depends on the show collision debug settings.
</member>
<member name="navigation_visibility_mode" type="int" setter="set_navigation_visibility_mode" getter="get_navigation_visibility_mode" enum="TileMap.VisibilityMode" default="0">
- Show or hide the TileMap's collision shapes. If set to [constant VISIBILITY_MODE_DEFAULT], this depends on the show navigation debug settings.
+ Show or hide the TileMap's navigation meshes. If set to [constant VISIBILITY_MODE_DEFAULT], this depends on the show navigation debug settings.
</member>
<member name="tile_set" type="TileSet" setter="set_tileset" getter="get_tileset">
The assigned [TileSet].
diff --git a/doc/classes/VSlider.xml b/doc/classes/VSlider.xml
index b30349e538..488154106f 100644
--- a/doc/classes/VSlider.xml
+++ b/doc/classes/VSlider.xml
@@ -33,6 +33,7 @@
The background of the area below the grabber.
</theme_item>
<theme_item name="grabber_area_highlight" data_type="style" type="StyleBox">
+ The background of the area below the grabber, to the left of the grabber.
</theme_item>
<theme_item name="slider" data_type="style" type="StyleBox">
The background for the whole slider. Determines the width of the [code]grabber_area[/code].
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 998e782975..fce94fe567 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -71,6 +71,12 @@
<description>
</description>
</method>
+ <method name="get_screen_transform" qualifiers="const">
+ <return type="Transform2D" />
+ <description>
+ Returns the transform from the Viewport's coordinates to the screen coordinates of the containing window manager window.
+ </description>
+ </method>
<method name="get_texture" qualifiers="const">
<return type="ViewportTexture" />
<description>
diff --git a/doc/classes/ViewportTexture.xml b/doc/classes/ViewportTexture.xml
index 87de664aad..6bd64a50bb 100644
--- a/doc/classes/ViewportTexture.xml
+++ b/doc/classes/ViewportTexture.xml
@@ -6,6 +6,7 @@
<description>
Displays the content of a [Viewport] node as a dynamic [Texture2D]. This can be used to mix controls, 2D, and 3D elements in the same scene.
To create a ViewportTexture in code, use the [method Viewport.get_texture] method on the target viewport.
+ [b]Note:[/b] When local to scene, this texture uses [method Resource.setup_local_to_scene] to set the proxy texture and flags in the local viewport.
</description>
<tutorials>
<link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link>
diff --git a/doc/classes/VisibleOnScreenEnabler2D.xml b/doc/classes/VisibleOnScreenEnabler2D.xml
index 50d0c00017..8590e9cc9f 100644
--- a/doc/classes/VisibleOnScreenEnabler2D.xml
+++ b/doc/classes/VisibleOnScreenEnabler2D.xml
@@ -1,23 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisibleOnScreenEnabler2D" inherits="VisibleOnScreenNotifier2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Automatically disables another node if not visible on screen.
</brief_description>
<description>
+ VisibleOnScreenEnabler2D detects when it is visible on screen (just like [VisibleOnScreenNotifier2D]) and automatically enables or disables the target node. The target node is disabled when [VisibleOnScreenEnabler2D] is not visible on screen (including when [member CanvasItem.visible] is [code]false[/code]), and enabled when the enabler is visible. The disabling is achieved by changing [member Node.process_mode].
</description>
<tutorials>
</tutorials>
<members>
<member name="enable_mode" type="int" setter="set_enable_mode" getter="get_enable_mode" enum="VisibleOnScreenEnabler2D.EnableMode" default="0">
+ Determines how the node is enabled. Corresponds to [enum Node.ProcessMode]. Disabled node uses [constant Node.PROCESS_MODE_DISABLED].
</member>
<member name="enable_node_path" type="NodePath" setter="set_enable_node_path" getter="get_enable_node_path" default="NodePath(&quot;..&quot;)">
+ The path to the target node, relative to the [VisibleOnScreenEnabler2D]. The target node is cached; it's only assigned when setting this property (if the [VisibleOnScreenEnabler2D] is inside scene tree) and every time the [VisibleOnScreenEnabler2D] enters the scene tree. If the path is invalid, nothing will happen.
</member>
</members>
<constants>
<constant name="ENABLE_MODE_INHERIT" value="0" enum="EnableMode">
+ Corresponds to [constant Node.PROCESS_MODE_INHERIT].
</constant>
<constant name="ENABLE_MODE_ALWAYS" value="1" enum="EnableMode">
+ Corresponds to [constant Node.PROCESS_MODE_ALWAYS].
</constant>
<constant name="ENABLE_MODE_WHEN_PAUSED" value="2" enum="EnableMode">
+ Corresponds to [constant Node.PROCESS_MODE_WHEN_PAUSED.
</constant>
</constants>
</class>
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
index 9574686506..94e8c25660 100644
--- a/doc/classes/VisualInstance3D.xml
+++ b/doc/classes/VisualInstance3D.xml
@@ -17,7 +17,7 @@
<method name="get_aabb" qualifiers="const">
<return type="AABB" />
<description>
- Returns the [AABB] (also known as the bounding box) for this [VisualInstance3D]. See also [method get_transformed_aabb].
+ Returns the [AABB] (also known as the bounding box) for this [VisualInstance3D].
</description>
</method>
<method name="get_base" qualifiers="const">
@@ -39,13 +39,6 @@
Returns whether or not the specified layer of the [member layers] is enabled, given a [code]layer_number[/code] between 1 and 20.
</description>
</method>
- <method name="get_transformed_aabb" qualifiers="const">
- <return type="AABB" />
- <description>
- Returns the transformed [AABB] (also known as the bounding box) for this [VisualInstance3D].
- Transformed in this case means the [AABB] plus the position, rotation, and scale of the [Node3D]'s [Transform3D]. See also [method get_aabb].
- </description>
- </method>
<method name="set_base">
<return type="void" />
<param index="0" name="base" type="RID" />
diff --git a/doc/classes/XRPose.xml b/doc/classes/XRPose.xml
index 0e58fab9b3..31a484ea40 100644
--- a/doc/classes/XRPose.xml
+++ b/doc/classes/XRPose.xml
@@ -30,7 +30,7 @@
<member name="name" type="StringName" setter="set_name" getter="get_name" default="&amp;&quot;&quot;">
The name of this pose. Pose names are often driven by an action map setup by the user. Godot does suggest a number of pose names that it expects [XRInterface]s to implement:
- [code]root[/code] defines a root location, often used for tracked objects that do not have further nodes.
- - [code]aim[/code] defines the tip of a controller with the orientation pointing outwards, for instance: add your raycasts to this.
+ - [code]aim[/code] defines the tip of a controller with the orientation pointing outwards, for example: add your raycasts to this.
- [code]grip[/code] defines the location where the user grips the controller
- [code]skeleton[/code] defines the root location a hand mesh should be placed when using hand tracking and the animated skeleton supplied by the XR runtime.
</member>
@@ -46,7 +46,7 @@
No tracking information is available for this pose.
</constant>
<constant name="XR_TRACKING_CONFIDENCE_LOW" value="1" enum="TrackingConfidence">
- Tracking information may be inaccurate or estimated. For instance with inside out tracking this would indicate a controller may be (partially) obscured.
+ Tracking information may be inaccurate or estimated. For example, with inside out tracking this would indicate a controller may be (partially) obscured.
</constant>
<constant name="XR_TRACKING_CONFIDENCE_HIGH" value="2" enum="TrackingConfidence">
Tracking information is deemed accurate and up to date.
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index 48b00323d3..d940ea41ac 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -30,18 +30,18 @@
<param index="1" name="keep_height" type="bool" />
<description>
This is an important function to understand correctly. AR and VR platforms all handle positioning slightly differently.
- For platforms that do not offer spatial tracking, our origin point (0,0,0) is the location of our HMD, but you have little control over the direction the player is facing in the real world.
+ For platforms that do not offer spatial tracking, our origin point (0, 0, 0) is the location of our HMD, but you have little control over the direction the player is facing in the real world.
For platforms that do offer spatial tracking, our origin point depends very much on the system. For OpenVR, our origin point is usually the center of the tracking space, on the ground. For other platforms, it's often the location of the tracking camera.
This method allows you to center your tracker on the location of the HMD. It will take the current location of the HMD and use that to adjust all your tracking data; in essence, realigning the real world to your player's current position in the game world.
For this method to produce usable results, tracking information must be available. This often takes a few frames after starting your game.
- You should call this method after a few seconds have passed. For instance, when the user requests a realignment of the display holding a designated button on a controller for a short period of time, or when implementing a teleport mechanism.
+ You should call this method after a few seconds have passed. For example, when the user requests a realignment of the display holding a designated button on a controller for a short period of time, or when implementing a teleport mechanism.
</description>
</method>
<method name="find_interface" qualifiers="const">
<return type="XRInterface" />
<param index="0" name="name" type="String" />
<description>
- Finds an interface by its [param name]. For instance, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it.
+ Finds an interface by its [param name]. For example, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it.
</description>
</method>
<method name="get_hmd_transform">
diff --git a/doc/classes/float.xml b/doc/classes/float.xml
index 9d685b9cd0..d7232bb0e9 100644
--- a/doc/classes/float.xml
+++ b/doc/classes/float.xml
@@ -194,7 +194,7 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] the left float is less than the right one.
+ Returns [code]true[/code] if the left float is less than the right one.
</description>
</operator>
<operator name="operator &lt;">
@@ -208,7 +208,7 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] the left integer is less than or equal to the right one.
+ Returns [code]true[/code] if the left float is less than or equal to the right one.
</description>
</operator>
<operator name="operator &lt;=">
@@ -237,7 +237,7 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] the left float is greater than the right one.
+ Returns [code]true[/code] if the left float is greater than the right one.
</description>
</operator>
<operator name="operator &gt;">
@@ -251,7 +251,7 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] the left float is greater than or equal to the right one.
+ Returns [code]true[/code] if the left float is greater than or equal to the right one.
</description>
</operator>
<operator name="operator &gt;=">
diff --git a/doc/classes/int.xml b/doc/classes/int.xml
index 78e2e7d18f..868a8e9944 100644
--- a/doc/classes/int.xml
+++ b/doc/classes/int.xml
@@ -72,14 +72,14 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] if operands are different from each other.
+ Returns [code]true[/code] if this [int] is not equivalent to the given [float].
</description>
</operator>
<operator name="operator !=">
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] if operands are different from each other.
+ Returns [code]true[/code] if the integers are not equal.
</description>
</operator>
<operator name="operator %">
@@ -262,7 +262,7 @@
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] the left integer is less than the right one.
+ Returns [code]true[/code] if the left integer is less than the right one.
</description>
</operator>
<operator name="operator &lt;&lt;">
@@ -287,7 +287,7 @@
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] the left integer is less than or equal to the right one.
+ Returns [code]true[/code] if the left integer is less than or equal to the right one.
</description>
</operator>
<operator name="operator ==">
@@ -315,7 +315,7 @@
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] the left integer is greater than the right one.
+ Returns [code]true[/code] if the left integer is greater than the right one.
</description>
</operator>
<operator name="operator &gt;=">
@@ -329,7 +329,7 @@
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] the left integer is greater than or equal to the right one.
+ Returns [code]true[/code] if the left integer is greater than or equal to the right one.
</description>
</operator>
<operator name="operator &gt;&gt;">
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 0836a21254..ea97dff522 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -274,15 +274,32 @@ RasterizerGLES3::~RasterizerGLES3() {
void RasterizerGLES3::prepare_for_blitting_render_targets() {
}
-void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect) {
+void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer) {
GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(p_render_target);
+
ERR_FAIL_COND(!rt);
- glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
+ GLuint read_fbo = 0;
+ if (rt->view_count > 1) {
+ glGenFramebuffers(1, &read_fbo);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, p_layer);
+ } else {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
+ }
+
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
// Flip content upside down to correct for coordinates.
- glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, 0, p_screen_rect.size.y, p_screen_rect.size.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ Vector2i screen_rect_end = p_screen_rect.get_end();
+ glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
+ p_screen_rect.position.x, screen_rect_end.y, screen_rect_end.x, p_screen_rect.position.y,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ if (read_fbo != 0) {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glDeleteFramebuffers(1, &read_fbo);
+ }
}
// is this p_screen useless in a multi window environment?
@@ -293,7 +310,7 @@ void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_sc
RID rid_rt = blit.render_target;
Rect2 dst_rect = blit.dst_rect;
- _blit_render_target_to_screen(rid_rt, p_screen, dst_rect);
+ _blit_render_target_to_screen(rid_rt, p_screen, dst_rect, blit.multi_view.use_layer ? blit.multi_view.layer : 0);
}
}
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index 431515fd0d..d7d26685b4 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -68,7 +68,7 @@ protected:
RasterizerCanvasGLES3 *canvas = nullptr;
RasterizerSceneGLES3 *scene = nullptr;
- void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect);
+ void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer);
public:
RendererUtilities *get_utilities() { return utilities; }
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index d6486801e7..da713a5259 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1273,6 +1273,19 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
GLES3::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
GLES3::MaterialStorage::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix);
+ if (p_render_data->view_count > 1) {
+ for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ projection = correction * p_render_data->view_projection[v];
+ GLES3::MaterialStorage::store_camera(projection, scene_state.multiview_ubo.projection_matrix_view[v]);
+ GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.multiview_ubo.inv_projection_matrix_view[v]);
+
+ scene_state.multiview_ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
+ scene_state.multiview_ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
+ scene_state.multiview_ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
+ scene_state.multiview_ubo.eye_offset[v][3] = 0.0;
+ }
+ }
+
scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
scene_state.ubo.z_far = p_render_data->z_far;
@@ -1374,6 +1387,15 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ if (p_render_data->view_count > 1) {
+ if (scene_state.multiview_buffer == 0) {
+ glGenBuffers(1, &scene_state.multiview_buffer);
+ }
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
}
// Puts lights into Uniform Buffers. Needs to be called before _fill_list as this caches the index of each light in the Uniform Buffer
@@ -1916,8 +1938,14 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
GLES3::SceneShaderData *prev_shader = nullptr;
GeometryInstanceGLES3 *prev_inst = nullptr;
SceneShaderGLES3::ShaderVariant prev_variant = SceneShaderGLES3::ShaderVariant::MODE_COLOR;
+ SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized
- SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized.
+ // @todo Get this from p_params->spec_constant_base_flags instead of hardcoding it.
+ uint32_t base_spec_constants = 0;
+
+ if (p_render_data->view_count > 1) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_USE_MULTIVIEW;
+ }
switch (p_pass_mode) {
case PASS_MODE_COLOR:
@@ -1957,8 +1985,6 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
continue;
}
- //uint32_t base_spec_constants = p_params->spec_constant_base_flags;
-
GLES3::SceneShaderData *shader;
GLES3::SceneMaterialData *material_data;
void *mesh_surface;
@@ -2128,7 +2154,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
if (prev_shader != shader || prev_variant != instance_variant) {
- material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant);
+ material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant, base_spec_constants);
float opaque_prepass_threshold = 0.0;
if constexpr (p_pass_mode == PASS_MODE_DEPTH) {
opaque_prepass_threshold = 0.99;
@@ -2136,7 +2162,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
opaque_prepass_threshold = 0.1;
}
- material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant, base_spec_constants);
prev_shader = shader;
prev_variant = instance_variant;
@@ -2144,21 +2170,21 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
if (prev_inst != inst || prev_shader != shader || prev_variant != instance_variant) {
// Rebind the light indices.
- material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant);
- material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant, base_spec_constants);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant, base_spec_constants);
if (inst->omni_light_count) {
- glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant), inst->omni_light_count, inst->omni_light_gl_cache.ptr());
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant, base_spec_constants), inst->omni_light_count, inst->omni_light_gl_cache.ptr());
}
if (inst->spot_light_count) {
- glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant), inst->spot_light_count, inst->spot_light_gl_cache.ptr());
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant, base_spec_constants), inst->spot_light_count, inst->spot_light_gl_cache.ptr());
}
prev_inst = inst;
}
- material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, base_spec_constants);
if (inst->instance_count > 0) {
// Using MultiMesh.
// Bind instance buffers.
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 3895620228..3a759425e2 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -74,6 +74,7 @@ enum SceneUniformLocation {
SCENE_OMNILIGHT_UNIFORM_LOCATION,
SCENE_SPOTLIGHT_UNIFORM_LOCATION,
SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
+ SCENE_MULTIVIEW_UNIFORM_LOCATION,
};
enum SkyUniformLocation {
@@ -90,6 +91,8 @@ enum {
SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 2,
SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 3,
SPEC_CONSTANT_DISABLE_FOG = 4,
+ SPEC_CONSTANT_USE_RADIANCE_MAP = 5,
+ SPEC_CONSTANT_USE_MULTIVIEW = 6,
};
struct RenderDataGLES3 {
@@ -343,6 +346,13 @@ private:
};
static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
+ struct MultiviewUBO {
+ float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4];
+ };
+ static_assert(sizeof(MultiviewUBO) % 16 == 0, "Multiview UBO size must be a multiple of 16 bytes");
+
struct TonemapUBO {
float exposure = 1.0;
float white = 1.0;
@@ -353,6 +363,8 @@ private:
UBO ubo;
GLuint ubo_buffer = 0;
+ MultiviewUBO multiview_ubo;
+ GLuint multiview_buffer = 0;
GLuint tonemap_buffer = 0;
bool used_depth_prepass = false;
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 033f10dbc5..2ff7f72180 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -142,7 +142,7 @@ RID ShaderGLES3::version_create() {
return version_owner.make_rid(version);
}
-void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization) {
+void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization) {
#ifdef GLES_OVER_GL
builder.append("#version 330\n");
builder.append("#define USE_GLES_OVER_GL\n");
@@ -171,6 +171,24 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
}
builder.append("\n"); //make sure defines begin at newline
+ // Insert multiview extension loading, because it needs to appear before
+ // any non-preprocessor code (like the "precision highp..." lines below).
+ builder.append("#ifdef USE_MULTIVIEW\n");
+ builder.append("#if defined(GL_OVR_multiview2)\n");
+ builder.append("#extension GL_OVR_multiview2 : require\n");
+ builder.append("#elif defined(GL_OVR_multiview)\n");
+ builder.append("#extension GL_OVR_multiview : require\n");
+ builder.append("#endif\n");
+ if (p_stage_type == StageType::STAGE_TYPE_VERTEX) {
+ builder.append("layout(num_views=2) in;\n");
+ }
+ builder.append("#define ViewIndex gl_ViewID_OVR\n");
+ builder.append("#define MAX_VIEWS 2\n");
+ builder.append("#else\n");
+ builder.append("#define ViewIndex 0\n");
+ builder.append("#define MAX_VIEWS 1\n");
+ builder.append("#endif\n");
+
// Default to highp precision unless specified otherwise.
builder.append("precision highp float;\n");
builder.append("precision highp int;\n");
@@ -180,8 +198,9 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
builder.append("precision highp sampler2DArray;\n");
#endif
- for (uint32_t i = 0; i < p_template.chunks.size(); i++) {
- const StageTemplate::Chunk &chunk = p_template.chunks[i];
+ const StageTemplate &stage_template = stage_templates[p_stage_type];
+ for (uint32_t i = 0; i < stage_template.chunks.size(); i++) {
+ const StageTemplate::Chunk &chunk = stage_template.chunks[i];
switch (chunk.type) {
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
@@ -224,7 +243,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
//vertex stage
{
StringBuilder builder;
- _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX], p_specialization);
+ _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_VERTEX, p_specialization);
spec.vert_id = glCreateShader(GL_VERTEX_SHADER);
String builder_string = builder.as_string();
@@ -272,7 +291,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
//fragment stage
{
StringBuilder builder;
- _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT], p_specialization);
+ _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_FRAGMENT, p_specialization);
spec.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
String builder_string = builder.as_string();
@@ -413,7 +432,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver
{
StringBuilder builder;
- _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX], specialization_default_mask);
+ _build_variant_code(builder, i, version, STAGE_TYPE_VERTEX, specialization_default_mask);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "vertex";
@@ -425,7 +444,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver
//fragment stage
{
StringBuilder builder;
- _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT], specialization_default_mask);
+ _build_variant_code(builder, i, version, STAGE_TYPE_FRAGMENT, specialization_default_mask);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "fragment";
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 2b72549b5b..760b5e5ddb 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -153,7 +153,7 @@ private:
StageTemplate stage_templates[STAGE_TYPE_MAX];
- void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization);
+ void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization);
void _add_stage(const char *p_code, StageType p_stage_type);
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index efd6036ba9..2bd93796bd 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -16,6 +16,7 @@ DISABLE_LIGHT_OMNI = false
DISABLE_LIGHT_SPOT = false
DISABLE_FOG = false
USE_RADIANCE_MAP = true
+USE_MULTIVIEW = false
#[vertex]
@@ -153,6 +154,15 @@ layout(std140) uniform SceneData { // ubo:2
}
scene_data;
+#ifdef USE_MULTIVIEW
+layout(std140) uniform MultiviewData { // ubo:8
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp vec4 eye_offset[MAX_VIEWS];
+}
+multiview_data;
+#endif
+
uniform highp mat4 world_transform;
#ifdef USE_LIGHTMAP
@@ -250,8 +260,14 @@ void main() {
#if defined(OVERRIDE_POSITION)
highp vec4 position;
#endif
- highp mat4 projection_matrix = scene_data.projection_matrix;
- highp mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
+
+#ifdef USE_MULTIVIEW
+ mat4 projection_matrix = multiview_data.projection_matrix_view[ViewIndex];
+ mat4 inv_projection_matrix = multiview_data.inv_projection_matrix_view[ViewIndex];
+#else
+ mat4 projection_matrix = scene_data.projection_matrix;
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
+#endif //USE_MULTIVIEW
#ifdef USE_INSTANCING
vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w));
@@ -339,7 +355,6 @@ void main() {
/* clang-format off */
#[fragment]
-
// Default to SPECULAR_SCHLICK_GGX.
#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)
#define SPECULAR_SCHLICK_GGX
@@ -463,6 +478,15 @@ layout(std140) uniform SceneData { // ubo:2
}
scene_data;
+#ifdef USE_MULTIVIEW
+layout(std140) uniform MultiviewData { // ubo:8
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp vec4 eye_offset[MAX_VIEWS];
+}
+multiview_data;
+#endif
+
/* clang-format off */
#GLOBALS
@@ -530,8 +554,13 @@ uniform highp samplerCubeShadow positional_shadow; // texunit:-4
#endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
-uniform highp sampler2D screen_texture; // texunit:-5
+#ifdef USE_MULTIVIEW
+uniform highp sampler2DArray depth_buffer; // texunit:-6
+uniform highp sampler2DArray screen_texture; // texunit:-5
+#else
uniform highp sampler2D depth_buffer; // texunit:-6
+uniform highp sampler2D screen_texture; // texunit:-5
+#endif
uniform highp mat4 world_transform;
uniform mediump float opaque_prepass_threshold;
@@ -884,7 +913,11 @@ vec4 fog_process(vec3 vertex) {
void main() {
//lay out everything, whatever is unused is optimized away anyway
vec3 vertex = vertex_interp;
+#ifdef USE_MULTIVIEW
+ vec3 view = -normalize(vertex_interp - multiview_data.eye_offset[ViewIndex].xyz);
+#else
vec3 view = -normalize(vertex_interp);
+#endif
vec3 albedo = vec3(1.0);
vec3 backlight = vec3(0.0);
vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0);
diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl
index a478cf9170..0b769e77f2 100644
--- a/drivers/gles3/shaders/tonemap.glsl
+++ b/drivers/gles3/shaders/tonemap.glsl
@@ -44,7 +44,11 @@ in vec2 uv_interp;
layout(location = 0) out vec4 frag_color;
+#ifdef USE_MULTIVIEW
+uniform highp sampler2DArray source; //texunit:0
+#else
uniform highp sampler2D source; //texunit:0
+#endif
#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
#define USING_GLOW // only use glow when at least one glow level is selected
@@ -191,10 +195,17 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
const float FXAA_REDUCE_MUL = (1.0 / 8.0);
const float FXAA_SPAN_MAX = 8.0;
+#ifdef USE_MULTIVIEW
+ vec3 rgbNW = textureLod(source, vec3(uv_interp + vec2(-1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz;
+ vec3 rgbNE = textureLod(source, vec3(uv_interp + vec2(1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz;
+ vec3 rgbSW = textureLod(source, vec3(uv_interp + vec2(-1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz;
+ vec3 rgbSE = textureLod(source, vec3(uv_interp + vec2(1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz;
+#else
vec3 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz;
vec3 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz;
vec3 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz;
vec3 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz;
+#endif
vec3 rgbM = color;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
@@ -219,8 +230,13 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
dir * rcpDirMin)) *
pixel_size;
+#ifdef USE_MULTIVIEW
+ vec3 rgbA = 0.5 * (textureLod(source, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz);
+ vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz);
+#else
vec3 rgbA = 0.5 * (textureLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz);
vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source, uv_interp + dir * 0.5, 0.0).xyz);
+#endif
float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
@@ -231,7 +247,11 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
}
void main() {
+#ifdef USE_MULTIVIEW
+ vec4 color = textureLod(source, vec3(uv_interp, ViewIndex), 0.0);
+#else
vec4 color = textureLod(source, uv_interp, 0.0);
+#endif
#ifdef USE_FXAA
color.rgb = apply_fxaa(color.rgb, uv_interp, pixel_size);
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 242c1ce0a9..609ecacded 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -34,6 +34,15 @@
#include "core/config/project_settings.h"
#include "core/templates/vector.h"
+#ifdef ANDROID_ENABLED
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <GLES3/gl3platform.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
+
using namespace GLES3;
#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
@@ -98,6 +107,16 @@ Config::Config() {
anisotropic_level = MIN(float(1 << int(ProjectSettings::get_singleton()->get("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
}
+ multiview_supported = extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview");
+#ifdef ANDROID_ENABLED
+ if (multiview_supported) {
+ eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR");
+ if (eglFramebufferTextureMultiviewOVR == nullptr) {
+ multiview_supported = false;
+ }
+ }
+#endif
+
force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter");
diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h
index fe18345775..de08385e04 100644
--- a/drivers/gles3/storage/config.h
+++ b/drivers/gles3/storage/config.h
@@ -44,6 +44,10 @@
#include OPENGL_INCLUDE_H
#endif
+#ifdef ANDROID_ENABLED
+typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei);
+#endif
+
namespace GLES3 {
class Config {
@@ -82,6 +86,11 @@ public:
bool support_anisotropic_filter = false;
float anisotropic_level = 0.0f;
+ bool multiview_supported = false;
+#ifdef ANDROID_ENABLED
+ PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
+#endif
+
static Config *get_singleton() { return singleton; };
Config();
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 22d84eba93..11ce31856d 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -309,12 +309,48 @@ RS::BlendShapeMode MeshStorage::mesh_get_blend_shape_mode(RID p_mesh) const {
}
void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+
+ uint64_t data_size = p_data.size();
+ ERR_FAIL_COND(p_offset + data_size > mesh->surfaces[p_surface]->vertex_buffer_size);
+ const uint8_t *r = p_data.ptr();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->vertex_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, data_size, r);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+
+ uint64_t data_size = p_data.size();
+ ERR_FAIL_COND(p_offset + data_size > mesh->surfaces[p_surface]->attribute_buffer_size);
+ const uint8_t *r = p_data.ptr();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->attribute_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, data_size, r);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+
+ uint64_t data_size = p_data.size();
+ ERR_FAIL_COND(p_offset + data_size > mesh->surfaces[p_surface]->skin_buffer_size);
+ const uint8_t *r = p_data.ptr();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->skin_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, data_size, r);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index 9123984dc7..b8e4530f56 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -33,12 +33,17 @@
#include "render_scene_buffers_gles3.h"
#include "texture_storage.h"
+#ifdef ANDROID_ENABLED
+#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
+#endif
+
RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data();
}
void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
//internal_size.x = p_internal_size.x; // ignore for now
//internal_size.y = p_internal_size.y;
@@ -50,7 +55,7 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte
//msaa = p_msaa;
//screen_space_aa = p_screen_space_aa;
//use_debanding = p_use_debanding;
- //view_count = p_view_count;
+ view_count = p_view_count;
free_render_buffer_data();
@@ -62,24 +67,43 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
- glBindTexture(GL_TEXTURE_2D, rt->color);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ if (view_count > 1 && config->multiview_supported) {
+ glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color);
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, view_count);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, rt->color);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ }
glGenTextures(1, &depth_texture);
- glBindTexture(GL_TEXTURE_2D, depth_texture);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (view_count > 1 && config->multiview_supported) {
+ glBindTexture(GL_TEXTURE_2D_ARRAY, depth_texture);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, depth_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
+ if (view_count > 1 && config->multiview_supported) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture, 0, 0, view_count);
+ } else {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
+ }
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindTexture(GL_TEXTURE_2D, 0);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
if (status != GL_FRAMEBUFFER_COMPLETE) {
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index ad0d2032b0..dbedbd22c3 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -56,7 +56,7 @@ public:
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
//RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
//bool use_debanding = false;
- //uint32_t view_count = 1;
+ uint32_t view_count = 1;
bool is_transparent = false;
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 554b4165fa..524ff14cc9 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -34,6 +34,10 @@
#include "config.h"
#include "drivers/gles3/effects/copy_effects.h"
+#ifdef ANDROID_ENABLED
+#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
+#endif
+
using namespace GLES3;
TextureStorage *TextureStorage::singleton = nullptr;
@@ -720,8 +724,7 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
}
void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
- // only 1 layer so far
- texture_set_data(p_texture, p_image);
+ texture_set_data(p_texture, p_image, p_layer);
#ifdef TOOLS_ENABLED
Texture *tex = texture_owner.get_or_null(p_texture);
@@ -1012,7 +1015,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
img->resize_to_po2(false);
}
- GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D;
+ GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : texture->target;
Vector<uint8_t> read = img->get_data();
@@ -1069,7 +1072,11 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
} else {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ if (texture->target == GL_TEXTURE_2D_ARRAY) {
+ glTexSubImage3D(GL_TEXTURE_2D_ARRAY, i, 0, 0, p_layer, w, h, 0, format, type, &read[ofs]);
+ } else {
+ glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ }
}
tsize += size;
@@ -1425,6 +1432,8 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
return;
}
+ Config *config = Config::get_singleton();
+
rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2;
rt->color_format = GL_RGBA;
rt->color_type = rt->is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
@@ -1446,17 +1455,29 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
// color
glGenTextures(1, &rt->color);
- glBindTexture(GL_TEXTURE_2D, rt->color);
-
- glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ if (rt->view_count > 1 && config->multiview_supported) {
+ glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, rt->color_internal_format, rt->size.x, rt->size.y, rt->view_count, 0, rt->color_format, rt->color_type, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, rt->color);
+ glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ if (rt->view_count > 1 && config->multiview_supported) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count);
+ } else {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ }
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -1475,8 +1496,15 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
texture->format = rt->image_format;
texture->real_format = rt->image_format;
- texture->type = Texture::TYPE_2D;
- texture->target = GL_TEXTURE_2D;
+ if (rt->view_count > 1 && config->multiview_supported) {
+ texture->type = Texture::TYPE_LAYERED;
+ texture->target = GL_TEXTURE_2D_ARRAY;
+ texture->layers = rt->view_count;
+ } else {
+ texture->type = Texture::TYPE_2D;
+ texture->target = GL_TEXTURE_2D;
+ texture->layers = 1;
+ }
texture->gl_format_cache = rt->color_format;
texture->gl_type_cache = GL_UNSIGNED_BYTE;
texture->gl_internal_format_cache = rt->color_internal_format;
@@ -1619,13 +1647,14 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
- if (p_width == rt->size.x && p_height == rt->size.y) {
+ if (p_width == rt->size.x && p_height == rt->size.y && p_view_count == rt->view_count) {
return;
}
_clear_render_target(rt);
rt->size = Size2i(p_width, p_height);
+ rt->view_count = p_view_count;
_update_render_target(rt);
}
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 39a74236e5..dbe39428ac 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -324,6 +324,7 @@ private:
struct RenderTarget {
Point2i position = Point2i(0, 0);
Size2i size = Size2i(0, 0);
+ uint32_t view_count = 1;
int mipmap_count = 1;
RID self;
GLuint fbo = 0;
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 831dd80d6e..9ee5a67471 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -1810,18 +1810,22 @@ Error VulkanContext::_update_swap_chain(Window *window) {
preTransform = surfCapabilities.currentTransform;
}
- // Find a supported composite alpha mode - one of these is guaranteed to be set.
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
- VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
- VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
- VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
- };
- for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
- if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
- compositeAlpha = compositeAlphaFlags[i];
- break;
+
+ if (OS::get_singleton()->is_layered_allowed() || !(surfCapabilities.supportedCompositeAlpha & compositeAlpha)) {
+ // Find a supported composite alpha mode - one of these is guaranteed to be set.
+ VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
+ VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ };
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
+ if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
+ compositeAlpha = compositeAlphaFlags[i];
+ break;
+ }
}
}
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 5c4ef35f1c..8a2d23d32d 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -6204,7 +6204,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
if (do_bake && !animation->track_is_compressed(i)) {
Animation::InterpolationType it = animation->track_get_interpolation_type(i);
if (it == Animation::INTERPOLATION_NEAREST) {
- continue; // Nearest and Angle interpolation cannot be baked.
+ continue; // Nearest interpolation cannot be baked.
}
// Special case for angle interpolation.
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 01816b7205..5545dc4ee2 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -958,6 +958,7 @@ EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) {
preview_rect->set_offset(SIDE_TOP, 1);
preview_rect->set_offset(SIDE_BOTTOM, -1);
preview_rect->set_offset(SIDE_RIGHT, -1);
+ preview_rect->set_texture_filter(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
assign_button->add_child(preview_rect);
}
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 4d3ffdc12b..e5d4b262aa 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -2435,6 +2435,7 @@ void Node3DEditorViewport::_notification(int p_what) {
bool vp_visible = is_visible_in_tree();
set_process(vp_visible);
+ set_physics_process(vp_visible);
if (vp_visible) {
orthogonal = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL));
@@ -2658,6 +2659,21 @@ void Node3DEditorViewport::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_PHYSICS_PROCESS: {
+ if (!update_preview_node) {
+ return;
+ }
+ if (preview_node->is_inside_tree()) {
+ preview_node_pos = _get_instance_position(preview_node_viewport_pos);
+ Transform3D preview_gl_transform = Transform3D(Basis(), preview_node_pos);
+ preview_node->set_global_transform(preview_gl_transform);
+ if (!preview_node->is_visible()) {
+ preview_node->show();
+ }
+ }
+ update_preview_node = false;
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
surface->connect("draw", callable_mp(this, &Node3DEditorViewport::_draw));
surface->connect("gui_input", callable_mp(this, &Node3DEditorViewport::_sinput));
@@ -4029,7 +4045,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
gl_transform = parent_node3d->get_global_gizmo_transform();
}
- gl_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
+ gl_transform.origin = spatial_editor->snap_point(preview_node_pos);
gl_transform.basis *= node3d->get_transform().basis;
editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_global_transform", gl_transform);
@@ -4093,7 +4109,9 @@ void Node3DEditorViewport::_perform_drop_data() {
}
}
-bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ preview_node_viewport_pos = p_point;
+
bool can_instantiate = false;
if (!preview_node->is_inside_tree() && spatial_editor->get_preview_material().is_null()) {
@@ -4157,6 +4175,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
}
if (can_instantiate) {
_create_preview_node(files);
+ preview_node->hide();
}
}
} else {
@@ -4166,8 +4185,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
}
if (can_instantiate) {
- Transform3D gl_transform = Transform3D(Basis(), _get_instance_position(p_point));
- preview_node->set_global_transform(gl_transform);
+ update_preview_node = true;
return true;
}
@@ -6932,6 +6950,10 @@ HashSet<RID> _get_physics_bodies_rid(Node *node) {
}
void Node3DEditor::snap_selected_nodes_to_floor() {
+ do_snap_selected_nodes_to_floor = true;
+}
+
+void Node3DEditor::_snap_selected_nodes_to_floor() {
const List<Node *> &selection = editor_selection->get_selected_node_list();
Dictionary snap_data;
@@ -6969,9 +6991,10 @@ void Node3DEditor::snap_selected_nodes_to_floor() {
}
}
if (!found_valid_shape && vi.size()) {
- AABB aabb = (*vi.begin())->get_transformed_aabb();
+ VisualInstance3D *begin = *vi.begin();
+ AABB aabb = begin->get_global_transform().xform(begin->get_aabb());
for (const VisualInstance3D *I : vi) {
- aabb.merge_with(I->get_transformed_aabb());
+ aabb.merge_with(I->get_global_transform().xform(I->get_aabb()));
}
Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5);
from = aabb.position + size;
@@ -7229,6 +7252,13 @@ void Node3DEditor::_notification(int p_what) {
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
}
} break;
+
+ case NOTIFICATION_PHYSICS_PROCESS: {
+ if (do_snap_selected_nodes_to_floor) {
+ _snap_selected_nodes_to_floor();
+ do_snap_selected_nodes_to_floor = false;
+ }
+ }
}
}
@@ -8349,10 +8379,12 @@ void Node3DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
spatial_editor->show();
spatial_editor->set_process(true);
+ spatial_editor->set_physics_process(true);
} else {
spatial_editor->hide();
spatial_editor->set_process(false);
+ spatial_editor->set_physics_process(false);
}
}
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index c76f534c22..7dbe153efd 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -193,6 +193,9 @@ private:
void _menu_option(int p_option);
void _set_auto_orthogonal();
Node3D *preview_node = nullptr;
+ bool update_preview_node = false;
+ Point2 preview_node_viewport_pos;
+ Vector3 preview_node_pos;
AABB *preview_bounds = nullptr;
Vector<String> selected_files;
AcceptDialog *accept = nullptr;
@@ -413,7 +416,7 @@ private:
bool _create_instance(Node *parent, String &path, const Point2 &p_point);
void _perform_drop_data();
- bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
void _project_settings_changed();
@@ -720,6 +723,9 @@ private:
void _selection_changed();
void _refresh_menu_icons();
+ bool do_snap_selected_nodes_to_floor = false;
+ void _snap_selected_nodes_to_floor();
+
// Preview Sun and Environment
uint32_t world_env_count = 0;
@@ -767,7 +773,7 @@ private:
WorldEnvironment *preview_environment = nullptr;
bool preview_env_dangling = false;
Ref<Environment> environment;
- Ref<CameraAttributesPhysical> camera_attributes;
+ Ref<CameraAttributesPractical> camera_attributes;
Ref<ProceduralSkyMaterial> sky_material;
bool sun_environ_updating = false;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 58a0160010..7d7ef9245f 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1598,9 +1598,24 @@ static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const
return nullptr;
}
-void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
- const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
+static String _quote_drop_data(const String &str) {
+ // This function prepares a string for being "dropped" into the script editor.
+ // The string can be a resource path, node path or property name.
+
+ const bool using_single_quotes = EDITOR_GET("text_editor/completion/use_single_quotes");
+
+ String escaped = str.c_escape();
+ // If string is double quoted, there is no need to escape single quotes.
+ // We can revert the extra escaping added in c_escape().
+ if (!using_single_quotes) {
+ escaped = escaped.replace("\\'", "\'");
+ }
+
+ return escaped.quote(using_single_quotes ? "'" : "\"");
+}
+
+void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
Dictionary d = p_data;
CodeEdit *te = code_editor->get_text_editor();
@@ -1638,9 +1653,9 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
if (preload) {
- text_to_drop += "preload(" + String(files[i]).c_escape().quote(quote_style) + ")";
+ text_to_drop += "preload(" + _quote_drop_data(String(files[i])) + ")";
} else {
- text_to_drop += String(files[i]).c_escape().quote(quote_style);
+ text_to_drop += _quote_drop_data(String(files[i]));
}
}
@@ -1686,7 +1701,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
for (const String &segment : path.split("/")) {
if (!segment.is_valid_identifier()) {
- path = path.c_escape().quote(quote_style);
+ path = _quote_drop_data(path);
break;
}
}
@@ -1721,7 +1736,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
for (const String &segment : path.split("/")) {
if (!segment.is_valid_identifier()) {
- path = path.c_escape().quote(quote_style);
+ path = _quote_drop_data(path);
break;
}
}
@@ -1737,7 +1752,9 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
if (d.has("type") && String(d["type"]) == "obj_property") {
te->remove_secondary_carets();
- const String text_to_drop = String(d["property"]).c_escape().quote(quote_style);
+ // It is unclear whether properties may contain single or double quotes.
+ // Assume here that double-quotes may not exist. We are escaping single-quotes if necessary.
+ const String text_to_drop = _quote_drop_data(String(d["property"]));
te->set_caret_line(row);
te->set_caret_column(col);
@@ -1978,18 +1995,6 @@ void ScriptTextEditor::_enable_code_editor() {
add_child(connection_info_dialog);
- edit_hb->add_child(search_menu);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
- search_menu->get_popup()->add_separator();
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
- search_menu->get_popup()->add_separator();
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL);
- search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
-
edit_hb->add_child(edit_menu);
edit_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_prepare_edit_menu));
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
@@ -2000,38 +2005,73 @@ void ScriptTextEditor::_enable_code_editor() {
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent"), EDIT_INDENT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unindent"), EDIT_UNINDENT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("line_menu");
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent"), EDIT_INDENT);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unindent"), EDIT_UNINDENT);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Line"), "line_menu");
+ }
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("folding_menu");
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Folding"), "folding_menu");
+ }
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT);
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("indent_menu");
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Indentation"), "indent_menu");
+ }
edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_separator();
-
- edit_menu->get_popup()->add_child(convert_case);
- edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case");
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4), EDIT_TO_UPPERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5), EDIT_TO_LOWERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6), EDIT_CAPITALIZE);
- convert_case->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
-
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("convert_case");
+ sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4), EDIT_TO_UPPERCASE);
+ sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5), EDIT_TO_LOWERCASE);
+ sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6), EDIT_CAPITALIZE);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case");
+ }
edit_menu->get_popup()->add_child(highlighter_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu");
highlighter_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_change_syntax_highlighter));
+ edit_hb->add_child(search_menu);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
+ search_menu->get_popup()->add_separator();
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
+ search_menu->get_popup()->add_separator();
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL);
+ search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+
_load_theme_settings();
edit_hb->add_child(goto_menu);
@@ -2106,9 +2146,6 @@ ScriptTextEditor::ScriptTextEditor() {
edit_menu->set_switch_on_hover(true);
edit_menu->set_shortcut_context(this);
- convert_case = memnew(PopupMenu);
- convert_case->set_name("convert_case");
-
highlighter_menu = memnew(PopupMenu);
highlighter_menu->set_name("highlighter_menu");
@@ -2153,7 +2190,6 @@ ScriptTextEditor::~ScriptTextEditor() {
memdelete(color_panel);
memdelete(edit_hb);
memdelete(edit_menu);
- memdelete(convert_case);
memdelete(highlighter_menu);
memdelete(search_menu);
memdelete(goto_menu);
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index fb02e5c7c4..c165295a8e 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -79,7 +79,6 @@ class ScriptTextEditor : public ScriptEditorBase {
PopupMenu *breakpoints_menu = nullptr;
PopupMenu *highlighter_menu = nullptr;
PopupMenu *context_menu = nullptr;
- PopupMenu *convert_case = nullptr;
GotoLineDialog *goto_line_dialog = nullptr;
ScriptEditorQuickOpen *quick_open = nullptr;
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index be382759f5..4aed7a92a2 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -29,7 +29,6 @@
/*************************************************************************/
#include "texture_editor_plugin.h"
-
#include "editor/editor_scale.h"
TextureRect *TexturePreview::get_texture_display() {
@@ -123,6 +122,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
add_child(checkerboard);
texture_display = memnew(TextureRect);
+ texture_display->set_texture_filter(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
texture_display->set_texture(p_texture);
texture_display->set_anchors_preset(TextureRect::PRESET_FULL_RECT);
texture_display->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index cbc95ef6d6..b9436e17f0 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -2348,27 +2348,27 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_path_o
}
HashMap<Vector2i, TileMapCell> output;
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- if (painted_set.has(E.key)) {
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
// Paint a random tile with the correct terrain for the painted path.
- output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ output[kv.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
} else {
// Avoids updating the painted path from the output if the new pattern is the same as before.
- bool keep_old = false;
- TileMapCell cell = tile_map->get_cell(tile_map_layer, E.key);
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = tile_map->get_cell(tile_map_layer, kv.key);
if (cell.source_id != TileSet::INVALID_SOURCE) {
TileSetSource *source = *tile_set->get_source(cell.source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
// Get tile data.
TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
- if (tile_data && tile_data->get_terrains_pattern() == E.value) {
- keep_old = true;
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
}
}
}
- if (!keep_old) {
- output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ if (in_map_terrain_pattern != kv.value) {
+ output[kv.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
}
}
}
@@ -2395,24 +2395,28 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_patter
}
HashMap<Vector2i, TileMapCell> output;
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- if (painted_set.has(E.key)) {
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
// Paint a random tile with the correct terrain for the painted path.
- output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ output[kv.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
} else {
// Avoids updating the painted path from the output if the new pattern is the same as before.
- TileMapCell cell = tile_map->get_cell(tile_map_layer, E.key);
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = tile_map->get_cell(tile_map_layer, kv.key);
if (cell.source_id != TileSet::INVALID_SOURCE) {
TileSetSource *source = *tile_set->get_source(cell.source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
// Get tile data.
TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
- if (tile_data && !(tile_data->get_terrains_pattern() == E.value)) {
- output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
}
}
}
+ if (in_map_terrain_pattern != kv.value) {
+ output[kv.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ }
}
}
return output;
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index 364c3b7246..6fdc9a80e8 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -66,7 +66,9 @@ void TilesEditorPlugin::_thread() {
pattern_preview_sem.wait();
pattern_preview_mutex.lock();
- if (pattern_preview_queue.size()) {
+ if (pattern_preview_queue.size() == 0) {
+ pattern_preview_mutex.unlock();
+ } else {
QueueItem item = pattern_preview_queue.front()->get();
pattern_preview_queue.pop_front();
pattern_preview_mutex.unlock();
@@ -130,8 +132,6 @@ void TilesEditorPlugin::_thread() {
item.callback.callp(args_ptr, 2, r, error);
viewport->queue_delete();
- } else {
- pattern_preview_mutex.unlock();
}
}
}
diff --git a/main/main.cpp b/main/main.cpp
index c990e01ee3..bb6ab11362 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1808,6 +1808,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
"0,33200,1,or_greater")); // No negative numbers
GLOBAL_DEF("display/window/ios/hide_home_indicator", true);
+ GLOBAL_DEF("display/window/ios/hide_status_bar", true);
+ GLOBAL_DEF("display/window/ios/suppress_ui_gesture", true);
GLOBAL_DEF("input_devices/pointing/ios/touch_delay", 0.15);
ProjectSettings::get_singleton()->set_custom_property_info("input_devices/pointing/ios/touch_delay",
PropertyInfo(Variant::FLOAT,
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index bc44479f93..c8eda53a2d 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -18,13 +18,11 @@
<param index="2" name="b8" type="int" />
<param index="3" name="a8" type="int" default="255" />
<description>
- Returns a color constructed from integer red, green, blue, and alpha channels. Each channel should have 8 bits of information ranging from 0 to 255.
- [code]r8[/code] red channel
- [code]g8[/code] green channel
- [code]b8[/code] blue channel
- [code]a8[/code] alpha channel
+ Returns a [Color] constructed from red ([param r8]), green ([param g8]), blue ([param b8]), and optionally alpha ([param a8]) integer channels, each divided by [code]255.0[/code] for their final value.
[codeblock]
- red = Color8(255, 0, 0)
+ var red = Color8(255, 0, 0) # Same as Color(1, 0, 0)
+ var dark_blue = Color8(0, 0, 51) # Same as Color(0, 0, 0.2).
+ var my_color = Color8(306, 255, 0, 102) # Same as Color(1.2, 1, 0, 0.4).
[/codeblock]
</description>
</method>
@@ -33,9 +31,9 @@
<param index="0" name="condition" type="bool" />
<param index="1" name="message" type="String" default="&quot;&quot;" />
<description>
- Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users.
- [b]Note:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode.
- The optional [code]message[/code] argument, if given, is shown in addition to the generic "Assertion failed" message. It must be a static string, so format strings can't be used. You can use this to provide additional details about why the assertion failed.
+ Asserts that the [param condition] is [code]true[/code]. If the [param condition] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users.
+ An optional [param message] can be shown in addition to the generic "Assertion failed" message. You can use this to provide additional details about why the assertion failed.
+ [b]Warning:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode.
[codeblock]
# Imagine we always want speed to be between 0 and 20.
var speed = -10
@@ -50,7 +48,7 @@
<return type="String" />
<param index="0" name="char" type="int" />
<description>
- Returns a character as a String of the given Unicode code point (which is compatible with ASCII code).
+ Returns a single character (as a [String]) of the given Unicode code point (which is compatible with ASCII code).
[codeblock]
a = char(65) # a is "A"
a = char(65 + 32) # a is "a"
@@ -63,14 +61,14 @@
<param index="0" name="what" type="Variant" />
<param index="1" name="type" type="int" />
<description>
- Converts from a type to another in the best way possible. The [code]type[/code] parameter uses the [enum Variant.Type] values.
+ Converts [param what] to [param type] in the best way possible. The [param type] uses the [enum Variant.Type] values.
[codeblock]
- a = Vector2(1, 0)
- # Prints 1
- print(a.length())
- a = convert(a, TYPE_STRING)
- # Prints 6 as "(1, 0)" is 6 characters
- print(a.length())
+ var a = [4, 2.5, 1.2]
+ print(a is Array) # Prints true
+
+ var b = convert(a, TYPE_PACKED_BYTE_ARRAY)
+ print(b) # Prints [4, 2, 1]
+ print(b is Array) # Prints false
[/codeblock]
</description>
</method>
@@ -78,7 +76,7 @@
<return type="Object" />
<param index="0" name="dictionary" type="Dictionary" />
<description>
- Converts a [param dictionary] (previously created with [method inst_to_dict]) back to an Object instance. Useful for deserializing.
+ Converts a [param dictionary] (created with [method inst_to_dict]) back to an Object instance. Can be useful for deserializing.
</description>
</method>
<method name="get_stack">
@@ -95,19 +93,19 @@
func bar():
print(get_stack())
[/codeblock]
- would print
+ Starting from [code]_ready()[/code], [code]bar()[/code] would print:
[codeblock]
[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]
[/codeblock]
- [b]Note:[/b] [method get_stack] only works if the running instance is connected to a debugging server (i.e. an editor instance). [method get_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
- [b]Note:[/b] Not supported for calling from threads. Instead, this will return an empty array.
+ [b]Note:[/b] This function only works if the running instance is connected to a debugging server (i.e. an editor instance). [method get_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
+ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will return an empty array.
</description>
</method>
<method name="inst_to_dict">
<return type="Dictionary" />
<param index="0" name="instance" type="Object" />
<description>
- Returns the passed [param instance] converted to a Dictionary (useful for serializing).
+ Returns the passed [param instance] converted to a Dictionary. Can be useful for serializing.
[codeblock]
var foo = "bar"
func _ready():
@@ -126,11 +124,13 @@
<return type="int" />
<param index="0" name="var" type="Variant" />
<description>
- Returns length of Variant [code]var[/code]. Length is the character count of String, element count of Array, size of Dictionary, etc.
- [b]Note:[/b] Generates a fatal error if Variant can not provide a length.
+ Returns the length of the given Variant [param var]. The length can be the character count of a [String], the element count of any array type or the size of a [Dictionary]. For every other Variant type, a run-time error is generated and execution is stopped.
[codeblock]
a = [1, 2, 3, 4]
len(a) # Returns 4
+
+ b = "Hello!"
+ len(b) # Returns 6
[/codeblock]
</description>
</method>
@@ -138,25 +138,25 @@
<return type="Resource" />
<param index="0" name="path" type="String" />
<description>
- Loads a resource from the filesystem located at [code]path[/code]. The resource is loaded on the method call (unless it's referenced already elsewhere, e.g. in another script or in the scene), which might cause slight delay, especially when loading scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload].
+ Returns a [Resource] from the filesystem located at the absolute [param path]. Unless it's already referenced elsewhere (such as in another script or in the scene), the resource is loaded from disk on function call, which might cause a slight delay, especially when loading large scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload].
[b]Note:[/b] Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script.
[codeblock]
- # Load a scene called main located in the root of the project directory and cache it in a variable.
+ # Load a scene called "main" located in the root of the project directory and cache it in a variable.
var main = load("res://main.tscn") # main will contain a PackedScene resource.
[/codeblock]
- [b]Important:[/b] The path must be absolute, a local path will just return [code]null[/code].
- This method is a simplified version of [method ResourceLoader.load], which can be used for more advanced scenarios.
- [b]Note:[/b] You have to import the files into the engine first to load them using [method load]. If you want to load [Image]s at run-time, you may use [method Image.load]. If you want to import audio files, you can use the snippet described in [member AudioStreamMP3.data].
+ [b]Important:[/b] The path must be absolute. A relative path will always return [code]null[/code].
+ This function is a simplified version of [method ResourceLoader.load], which can be used for more advanced scenarios.
+ [b]Note:[/b] Files have to be imported into the engine first to load them using this function. If you want to load [Image]s at run-time, you may use [method Image.load]. If you want to import audio files, you can use the snippet described in [member AudioStreamMP3.data].
</description>
</method>
<method name="preload">
<return type="Resource" />
<param index="0" name="path" type="String" />
<description>
- Returns a [Resource] from the filesystem located at [code]path[/code]. The resource is loaded during script parsing, i.e. is loaded with the script and [method preload] effectively acts as a reference to that resource. Note that the method requires a constant path. If you want to load a resource from a dynamic/variable path, use [method load].
+ Returns a [Resource] from the filesystem located at [param path]. During run-time, the resource is loaded when the script is being parsed. This function effectively acts as a reference to that resource. Note that this function requires [param path] to be a constant [String]. If you want to load a resource from a dynamic/variable path, use [method load].
[b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script.
[codeblock]
- # Instance a scene.
+ # Create instance of a scene.
var diamond = preload("res://diamond.tscn").instantiate()
[/codeblock]
</description>
@@ -165,24 +165,24 @@
<return type="void" />
<description>
Like [method @GlobalScope.print], but includes the current stack frame when running with the debugger turned on.
- Output in the console would look something like this:
+ The output in the console may look like the following:
[codeblock]
Test print
- At: res://test.gd:15:_process()
+ At: res://test.gd:15:_process()
[/codeblock]
- [b]Note:[/b] Not supported for calling from threads. Instead of the stack frame, this will print the thread ID.
+ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will instead print the thread ID.
</description>
</method>
<method name="print_stack">
<return type="void" />
<description>
Prints a stack trace at the current code location. See also [method get_stack].
- Output in the console would look something like this:
+ The output in the console may look like the following:
[codeblock]
Frame 0 - res://test.gd:16 in function '_process'
[/codeblock]
- [b]Note:[/b] [method print_stack] only works if the running instance is connected to a debugging server (i.e. an editor instance). [method print_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
- [b]Note:[/b] Not supported for calling from threads. Instead of the stack trace, this will print the thread ID.
+ [b]Note:[/b] This function only works if the running instance is connected to a debugging server (i.e. an editor instance). [method print_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
+ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will instead print the thread ID.
</description>
</method>
<method name="range" qualifiers="vararg">
@@ -229,7 +229,7 @@
<method name="str" qualifiers="vararg">
<return type="String" />
<description>
- Converts one or more arguments to string in the best way possible.
+ Converts one or more arguments to a [String] in the best way possible.
[codeblock]
var a = [10, 20, 30]
var b = str(a);
@@ -242,7 +242,7 @@
<return type="bool" />
<param index="0" name="type" type="StringName" />
<description>
- Returns whether the given [Object]-derived class exists in [ClassDB]. Note that [Variant] data types are not registered in [ClassDB].
+ Returns [code]true[/code] if the given [Object]-derived class exists in [ClassDB]. Note that [Variant] data types are not registered in [ClassDB].
[codeblock]
type_exists("Sprite2D") # Returns true
type_exists("NonExistentClass") # Returns false
@@ -259,11 +259,11 @@
</constant>
<constant name="INF" value="inf">
Positive floating-point infinity. This is the result of floating-point division when the divisor is [code]0.0[/code]. For negative infinity, use [code]-INF[/code]. Dividing by [code]-0.0[/code] will result in negative infinity if the numerator is positive, so dividing by [code]0.0[/code] is not the same as dividing by [code]-0.0[/code] (despite [code]0.0 == -0.0[/code] returning [code]true[/code]).
- [b]Note:[/b] Numeric infinity is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer number by [code]0[/code] will not result in [constant INF] and will result in a run-time error instead.
+ [b]Warning:[/b] Numeric infinity is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer number by [code]0[/code] will not result in [constant INF] and will result in a run-time error instead.
</constant>
<constant name="NAN" value="nan">
"Not a Number", an invalid floating-point value. [constant NAN] has special properties, including that it is not equal to itself ([code]NAN == NAN[/code] returns [code]false[/code]). It is output by some invalid operations, such as dividing floating-point [code]0.0[/code] by [code]0.0[/code].
- [b]Note:[/b] "Not a Number" is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer [code]0[/code] by [code]0[/code] will not result in [constant NAN] and will result in a run-time error instead.
+ [b]Warning:[/b] "Not a Number" is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer [code]0[/code] by [code]0[/code] will not result in [constant NAN] and will result in a run-time error instead.
</constant>
</constants>
<annotations>
@@ -294,7 +294,7 @@
<annotation name="@export_color_no_alpha">
<return type="void" />
<description>
- Export a [Color] property without an alpha (fixed as [code]1.0[/code]).
+ Export a [Color] property without transparency (its alpha fixed as [code]1.0[/code]).
See also [constant PROPERTY_HINT_COLOR_NO_ALPHA].
[codeblock]
@export_color_no_alpha var modulate_color: Color
@@ -320,7 +320,7 @@
[codeblock]
@export_enum("Rebecca", "Mary", "Leah") var character_name: String
@export_enum("Warrior", "Magician", "Thief") var character_class: int
- @export_enum("Walking:30", "Running:60", "Riding:200") var character_speed: int
+ @export_enum("Slow:30", "Average:60", "Very Fast:200") var character_speed: int
[/codeblock]
</description>
</annotation>
@@ -451,7 +451,7 @@
<description>
Define a new group for the following exported properties. This helps to organize properties in the Inspector dock. Groups can be added with an optional [param prefix], which would make group to only consider properties that have this prefix. The grouping will break on the first property that doesn't have a prefix. The prefix is also removed from the property's name in the Inspector dock.
If no [param prefix] is provided, the every following property is added to the group. The group ends when then next group or category is defined. You can also force end a group by using this annotation with empty strings for parameters, [code]@export_group("", "")[/code].
- Groups cannot be nested, use [annotation @export_subgroup] to add subgroups to your groups.
+ Groups cannot be nested, use [annotation @export_subgroup] to add subgroups within groups.
See also [constant PROPERTY_USAGE_GROUP].
[codeblock]
@export_group("My Properties")
@@ -473,7 +473,7 @@
Export a [String] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property.
See also [constant PROPERTY_HINT_MULTILINE_TEXT].
[codeblock]
- @export_multiline var character_bio
+ @export_multiline var character_biography
[/codeblock]
</description>
</annotation>
@@ -547,11 +547,11 @@
<return type="void" />
<param index="0" name="icon_path" type="String" />
<description>
- Add a custom icon to the current script. The icon is displayed in the Scene dock for every node that the script is attached to. For named classes the icon is also displayed in various editor dialogs.
+ Add a custom icon to the current script. After loading an icon at [param icon_path], the icon is displayed in the Scene dock for every node that the script is attached to. For named classes, the icon is also displayed in various editor dialogs.
[codeblock]
@icon("res://path/to/class/icon.svg")
[/codeblock]
- [b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported yet.
+ [b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported.
</description>
</annotation>
<annotation name="@onready">
@@ -590,7 +590,7 @@
<return type="void" />
<param index="0" name="warning" type="String" />
<description>
- Mark the following statement to ignore the specified warning. See [url=$DOCS_URL/tutorials/scripting/gdscript/warning_system.html]GDScript warning system[/url].
+ Mark the following statement to ignore the specified [param warning]. See [url=$DOCS_URL/tutorials/scripting/gdscript/warning_system.html]GDScript warning system[/url].
[codeblock]
func test():
print("hello")
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 578e7a34f3..8246c96c15 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -4,7 +4,7 @@
A script implemented in the GDScript programming language.
</brief_description>
<description>
- A script implemented in the GDScript programming language. The script extends the functionality of all objects that instance it.
+ A script implemented in the GDScript programming language. The script extends the functionality of all objects that instantiate it.
[method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 6fbdec863f..898e4eb1a6 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -3226,7 +3226,13 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
}
p_preload->resolved_path = p_preload->resolved_path.simplify_path();
if (!ResourceLoader::exists(p_preload->resolved_path)) {
- push_error(vformat(R"(Preload file "%s" does not exist.)", p_preload->resolved_path), p_preload->path);
+ Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
+
+ if (file_check->file_exists(p_preload->resolved_path)) {
+ push_error(vformat(R"(Preload file "%s" has no resource loaders (unrecognized file extension).)", p_preload->resolved_path), p_preload->path);
+ } else {
+ push_error(vformat(R"(Preload file "%s" does not exist.)", p_preload->resolved_path), p_preload->path);
+ }
} else {
// TODO: Don't load if validating: use completion cache.
p_preload->resource = ResourceLoader::load(p_preload->resolved_path);
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index 4d1aa89ac9..8e48066623 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -9,6 +9,25 @@
<tutorials>
<link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
</tutorials>
+ <methods>
+ <method name="get_additional_data">
+ <return type="Variant" />
+ <param index="0" name="extension_name" type="StringName" />
+ <description>
+ Gets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the return value can be anything you set. If nothing was set, the return value is null.
+ </description>
+ </method>
+ <method name="set_additional_data">
+ <return type="void" />
+ <param index="0" name="extension_name" type="StringName" />
+ <param index="1" name="additional_data" type="Variant" />
+ <description>
+ Sets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
+ </description>
+ </method>
+ </methods>
<members>
<member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1">
</member>
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 56f3a70631..d0740cf7ca 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -20,6 +20,14 @@
<description>
</description>
</method>
+ <method name="get_additional_data">
+ <return type="Variant" />
+ <param index="0" name="extension_name" type="StringName" />
+ <description>
+ Gets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the return value can be anything you set. If nothing was set, the return value is null.
+ </description>
+ </method>
<method name="get_animation_player">
<return type="AnimationPlayer" />
<param index="0" name="idx" type="int" />
@@ -120,6 +128,15 @@
<description>
</description>
</method>
+ <method name="set_additional_data">
+ <return type="void" />
+ <param index="0" name="extension_name" type="StringName" />
+ <param index="1" name="additional_data" type="Variant" />
+ <description>
+ Sets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
+ </description>
+ </method>
<method name="set_animations">
<return type="void" />
<param index="0" name="animations" type="GLTFAnimation[]" />
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 60192c67e6..ac5665e396 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -87,6 +87,8 @@ void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_animations"), &GLTFState::get_animations);
ClassDB::bind_method(D_METHOD("set_animations", "animations"), &GLTFState::set_animations);
ClassDB::bind_method(D_METHOD("get_scene_node", "idx"), &GLTFState::get_scene_node);
+ ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFState::get_additional_data);
+ ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFState::set_additional_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "json"), "set_json", "get_json"); // Dictionary
ADD_PROPERTY(PropertyInfo(Variant::INT, "major_version"), "set_major_version", "get_major_version"); // int
@@ -358,3 +360,11 @@ String GLTFState::get_base_path() {
void GLTFState::set_base_path(String p_base_path) {
base_path = p_base_path;
}
+
+Variant GLTFState::get_additional_data(const StringName &p_extension_name) {
+ return additional_data[p_extension_name];
+}
+
+void GLTFState::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) {
+ additional_data[p_extension_name] = p_additional_data;
+}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index afe7e82010..e24017b0fd 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -97,6 +97,7 @@ class GLTFState : public Resource {
HashMap<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton;
HashMap<ObjectID, HashMap<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin;
+ Dictionary additional_data;
protected:
static void _bind_methods();
@@ -191,6 +192,9 @@ public:
AnimationPlayer *get_animation_player(int idx);
+ Variant get_additional_data(const StringName &p_extension_name);
+ void set_additional_data(const StringName &p_extension_name, Variant p_additional_data);
+
//void set_scene_nodes(RBMap<GLTFNodeIndex, Node *> p_scene_nodes) {
// this->scene_nodes = p_scene_nodes;
//}
diff --git a/modules/gltf/structures/gltf_node.cpp b/modules/gltf/structures/gltf_node.cpp
index 86280603fa..6fd36f93b7 100644
--- a/modules/gltf/structures/gltf_node.cpp
+++ b/modules/gltf/structures/gltf_node.cpp
@@ -57,6 +57,8 @@ void GLTFNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_children", "children"), &GLTFNode::set_children);
ClassDB::bind_method(D_METHOD("get_light"), &GLTFNode::get_light);
ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light);
+ ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFNode::get_additional_data);
+ ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFNode::set_additional_data);
ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex
ADD_PROPERTY(PropertyInfo(Variant::INT, "height"), "set_height", "get_height"); // int
@@ -176,3 +178,11 @@ GLTFLightIndex GLTFNode::get_light() {
void GLTFNode::set_light(GLTFLightIndex p_light) {
light = p_light;
}
+
+Variant GLTFNode::get_additional_data(const StringName &p_extension_name) {
+ return additional_data[p_extension_name];
+}
+
+void GLTFNode::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) {
+ additional_data[p_extension_name] = p_additional_data;
+}
diff --git a/modules/gltf/structures/gltf_node.h b/modules/gltf/structures/gltf_node.h
index 1a57ea32e2..90a4fa99ed 100644
--- a/modules/gltf/structures/gltf_node.h
+++ b/modules/gltf/structures/gltf_node.h
@@ -53,6 +53,7 @@ private:
Vector3 scale = Vector3(1, 1, 1);
Vector<int> children;
GLTFLightIndex light = -1;
+ Dictionary additional_data;
protected:
static void _bind_methods();
@@ -96,6 +97,9 @@ public:
GLTFLightIndex get_light();
void set_light(GLTFLightIndex p_light);
+
+ Variant get_additional_data(const StringName &p_extension_name);
+ void set_additional_data(const StringName &p_extension_name, Variant p_additional_data);
};
#endif // GLTF_NODE_H
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
index 7ec3f88e5d..19fdd51dab 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
@@ -56,7 +56,7 @@ namespace GodotPlugins.Game
}
";
- context.AddSource("GodotPlugins.Game_Generated",
+ context.AddSource("GodotPlugins.Game.generated",
SourceText.From(source, Encoding.UTF8));
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
index 1ee31eb1a9..d915eeac0b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -87,7 +87,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptMethods_Generated";
+ + "_ScriptMethods.generated";
var source = new StringBuilder();
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
index e8a9e28d0c..ccfb405d26 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -96,8 +96,8 @@ namespace Godot.SourceGenerators
string.Empty;
bool hasNamespace = classNs.Length != 0;
- var uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptPath_Generated";
+ string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptPath.generated";
var source = new StringBuilder();
@@ -126,7 +126,7 @@ namespace Godot.SourceGenerators
source.Append("\n}\n");
}
- context.AddSource(uniqueHint.ToString(), SourceText.From(source.ToString(), Encoding.UTF8));
+ context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
}
private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context,
@@ -157,7 +157,7 @@ namespace Godot.SourceGenerators
sourceBuilder.Append("})]\n");
- context.AddSource("AssemblyScriptTypes_Generated",
+ context.AddSource("AssemblyScriptTypes.generated",
SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index b331e2e794..1198c633d9 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -73,7 +73,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptProperties_Generated";
+ + "_ScriptProperties.generated";
var source = new StringBuilder();
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
index 65dadcb801..98b9745c16 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -73,7 +73,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptPropertyDefVal_Generated";
+ + "_ScriptPropertyDefVal.generated";
var source = new StringBuilder();
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
index a40220565f..11e0a6fa21 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -73,7 +73,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptSerialization_Generated";
+ + "_ScriptSerialization.generated";
var source = new StringBuilder();
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index ea7cc3fe38..4e443ce26e 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -82,7 +82,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptSignals_Generated";
+ + "_ScriptSignals.generated";
var source = new StringBuilder();
diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp
index 9755f426d5..95857392c7 100644
--- a/modules/multiplayer/multiplayer_synchronizer.cpp
+++ b/modules/multiplayer/multiplayer_synchronizer.cpp
@@ -118,6 +118,10 @@ void MultiplayerSynchronizer::set_net_id(uint32_t p_net_id) {
}
bool MultiplayerSynchronizer::update_outbound_sync_time(uint64_t p_msec) {
+ if (last_sync_msec == p_msec) {
+ // last_sync_msec has been updated on this frame.
+ return true;
+ }
if (p_msec >= last_sync_msec + interval_msec) {
last_sync_msec = p_msec;
return true;
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp
index df9985916b..8359580805 100644
--- a/modules/multiplayer/scene_replication_interface.cpp
+++ b/modules/multiplayer/scene_replication_interface.cpp
@@ -261,11 +261,11 @@ Error SceneReplicationInterface::_update_sync_visibility(int p_peer, Multiplayer
if (p_peer == 0) {
for (KeyValue<int, PeerInfo> &E : peers_info) {
// Might be visible to this specific peer.
- is_visible = is_visible || p_sync->is_visible_to(E.key);
- if (is_visible == E.value.sync_nodes.has(sid)) {
+ bool is_visible_to_peer = is_visible || p_sync->is_visible_to(E.key);
+ if (is_visible_to_peer == E.value.sync_nodes.has(sid)) {
continue;
}
- if (is_visible) {
+ if (is_visible_to_peer) {
E.value.sync_nodes.insert(sid);
} else {
E.value.sync_nodes.erase(sid);
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 5ac167ad98..b5978ab134 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -96,6 +96,7 @@ env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_dep
env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extension_wrapper.cpp")
+env_openxr.add_source_files(module_obj, "extensions/openxr_fb_display_refresh_rate_extension.cpp")
env.modules_sources += module_obj
diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml
index 25bf496de9..f089fd066e 100644
--- a/modules/openxr/doc_classes/OpenXRInterface.xml
+++ b/modules/openxr/doc_classes/OpenXRInterface.xml
@@ -10,6 +10,19 @@
<tutorials>
<link title="Setting up XR">$DOCS_URL/tutorials/xr/setting_up_xr.html</link>
</tutorials>
+ <methods>
+ <method name="get_available_display_refresh_rates" qualifiers="const">
+ <return type="Array" />
+ <description>
+ Returns display refresh rates supported by the current HMD. Only returned if this feature is supported by the OpenXR runtime and after the interface has been initialized.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="display_refresh_rate" type="float" setter="set_display_refresh_rate" getter="get_display_refresh_rate" default="0.0">
+ The display refresh rate for the current HMD. Only functional if this feature is supported by the OpenXR runtime and after the interface has been initialized.
+ </member>
+ </members>
<signals>
<signal name="pose_recentered">
<description>
diff --git a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp
new file mode 100644
index 0000000000..c0bbaea5b4
--- /dev/null
+++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* openxr_fb_display_refresh_rate_extension.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "openxr_fb_display_refresh_rate_extension.h"
+
+OpenXRDisplayRefreshRateExtension *OpenXRDisplayRefreshRateExtension::singleton = nullptr;
+
+OpenXRDisplayRefreshRateExtension *OpenXRDisplayRefreshRateExtension::get_singleton() {
+ return singleton;
+}
+
+OpenXRDisplayRefreshRateExtension::OpenXRDisplayRefreshRateExtension(OpenXRAPI *p_openxr_api) :
+ OpenXRExtensionWrapper(p_openxr_api) {
+ singleton = this;
+
+ // Extensions we use for our hand tracking.
+ request_extensions[XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME] = &display_refresh_rate_ext;
+}
+
+OpenXRDisplayRefreshRateExtension::~OpenXRDisplayRefreshRateExtension() {
+ display_refresh_rate_ext = false;
+}
+
+void OpenXRDisplayRefreshRateExtension::on_instance_created(const XrInstance p_instance) {
+ if (display_refresh_rate_ext) {
+ EXT_INIT_XR_FUNC(xrEnumerateDisplayRefreshRatesFB);
+ EXT_INIT_XR_FUNC(xrGetDisplayRefreshRateFB);
+ EXT_INIT_XR_FUNC(xrRequestDisplayRefreshRateFB);
+ }
+}
+
+void OpenXRDisplayRefreshRateExtension::on_instance_destroyed() {
+ display_refresh_rate_ext = false;
+}
+
+float OpenXRDisplayRefreshRateExtension::get_refresh_rate() const {
+ float refresh_rate = 0.0;
+
+ if (display_refresh_rate_ext) {
+ float rate;
+ XrResult result = xrGetDisplayRefreshRateFB(openxr_api->get_session(), &rate);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to obtain refresh rate [", openxr_api->get_error_string(result), "]");
+ } else {
+ refresh_rate = rate;
+ }
+ }
+
+ return refresh_rate;
+}
+
+void OpenXRDisplayRefreshRateExtension::set_refresh_rate(float p_refresh_rate) {
+ if (display_refresh_rate_ext) {
+ XrResult result = xrRequestDisplayRefreshRateFB(openxr_api->get_session(), p_refresh_rate);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to set refresh rate [", openxr_api->get_error_string(result), "]");
+ }
+ }
+}
+
+Array OpenXRDisplayRefreshRateExtension::get_available_refresh_rates() const {
+ Array arr;
+ XrResult result;
+
+ if (display_refresh_rate_ext) {
+ uint32_t display_refresh_rate_count = 0;
+ result = xrEnumerateDisplayRefreshRatesFB(openxr_api->get_session(), 0, &display_refresh_rate_count, nullptr);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to obtain refresh rates count [", openxr_api->get_error_string(result), "]");
+ }
+
+ if (display_refresh_rate_count > 0) {
+ float *display_refresh_rates = (float *)memalloc(sizeof(float) * display_refresh_rate_count);
+ if (display_refresh_rates == nullptr) {
+ print_line("OpenXR: Failed to obtain refresh rates memory buffer [", openxr_api->get_error_string(result), "]");
+ return arr;
+ }
+
+ result = xrEnumerateDisplayRefreshRatesFB(openxr_api->get_session(), display_refresh_rate_count, &display_refresh_rate_count, display_refresh_rates);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to obtain refresh rates count [", openxr_api->get_error_string(result), "]");
+ memfree(display_refresh_rates);
+ return arr;
+ }
+
+ for (uint32_t i = 0; i < display_refresh_rate_count; i++) {
+ float refresh_rate = display_refresh_rates[i];
+ arr.push_back(Variant(refresh_rate));
+ }
+
+ memfree(display_refresh_rates);
+ }
+ }
+
+ return arr;
+}
diff --git a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h
new file mode 100644
index 0000000000..dcd52fe4d1
--- /dev/null
+++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h
@@ -0,0 +1,70 @@
+/*************************************************************************/
+/* openxr_fb_display_refresh_rate_extension.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
+#define OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
+
+// This extension gives us access to the possible display refresh rates
+// supported by the HMD.
+// While this is an FB extension it has been adopted by most runtimes and
+// will likely become core in the near future.
+
+#include "../openxr_api.h"
+#include "../util.h"
+
+#include "openxr_extension_wrapper.h"
+
+class OpenXRDisplayRefreshRateExtension : public OpenXRExtensionWrapper {
+public:
+ static OpenXRDisplayRefreshRateExtension *get_singleton();
+
+ OpenXRDisplayRefreshRateExtension(OpenXRAPI *p_openxr_api);
+ virtual ~OpenXRDisplayRefreshRateExtension() override;
+
+ virtual void on_instance_created(const XrInstance p_instance) override;
+ virtual void on_instance_destroyed() override;
+
+ float get_refresh_rate() const;
+ void set_refresh_rate(float p_refresh_rate);
+
+ Array get_available_refresh_rates() const;
+
+private:
+ static OpenXRDisplayRefreshRateExtension *singleton;
+
+ bool display_refresh_rate_ext = false;
+
+ // OpenXR API call wrappers
+ EXT_PROTO_XRRESULT_FUNC4(xrEnumerateDisplayRefreshRatesFB, (XrSession), session, (uint32_t), displayRefreshRateCapacityInput, (uint32_t *), displayRefreshRateCountOutput, (float *), displayRefreshRates);
+ EXT_PROTO_XRRESULT_FUNC2(xrGetDisplayRefreshRateFB, (XrSession), session, (float *), display_refresh_rate);
+ EXT_PROTO_XRRESULT_FUNC2(xrRequestDisplayRefreshRateFB, (XrSession), session, (float), display_refresh_rate);
+};
+
+#endif // OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
index 88cc7c061c..4d996e6283 100644
--- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
+++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
@@ -69,6 +69,34 @@ bool OpenXRHTCViveTrackerExtension::on_event_polled(const XrEventDataBuffer &eve
bool OpenXRHTCViveTrackerExtension::is_path_supported(const String &p_path) {
if (p_path == "/interaction_profiles/htc/vive_tracker_htcx") {
return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/handheld_object") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_foot") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_foot") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_shoulder") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_shoulder") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_elbow") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_elbow") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_knee") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_knee") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/waist") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/chest") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/chest") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/camera") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/keyboard") {
+ return available;
}
// Not a path under this extensions control, so we return true;
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 8a67462613..1ff1dac512 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -50,6 +50,7 @@
#endif
#include "extensions/openxr_composition_layer_depth_extension.h"
+#include "extensions/openxr_fb_display_refresh_rate_extension.h"
#include "extensions/openxr_fb_passthrough_extension_wrapper.h"
#include "extensions/openxr_hand_tracking_extension.h"
#include "extensions/openxr_htc_vive_tracker_extension.h"
@@ -443,12 +444,12 @@ bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType
for (uint32_t i = 0; i < view_count; i++) {
print_verbose("OpenXR: Found supported view configuration view");
- print_verbose(String(" - width: ") + view_configuration_views[i].maxImageRectWidth);
- print_verbose(String(" - height: ") + view_configuration_views[i].maxImageRectHeight);
- print_verbose(String(" - sample count: ") + view_configuration_views[i].maxSwapchainSampleCount);
- print_verbose(String(" - recommended render width: ") + view_configuration_views[i].recommendedImageRectWidth);
- print_verbose(String(" - recommended render height: ") + view_configuration_views[i].recommendedImageRectHeight);
- print_verbose(String(" - recommended render sample count: ") + view_configuration_views[i].recommendedSwapchainSampleCount);
+ print_verbose(String(" - width: ") + itos(view_configuration_views[i].maxImageRectWidth));
+ print_verbose(String(" - height: ") + itos(view_configuration_views[i].maxImageRectHeight));
+ print_verbose(String(" - sample count: ") + itos(view_configuration_views[i].maxSwapchainSampleCount));
+ print_verbose(String(" - recommended render width: ") + itos(view_configuration_views[i].recommendedImageRectWidth));
+ print_verbose(String(" - recommended render height: ") + itos(view_configuration_views[i].recommendedImageRectHeight));
+ print_verbose(String(" - recommended render sample count: ") + itos(view_configuration_views[i].recommendedSwapchainSampleCount));
}
return true;
@@ -1748,6 +1749,31 @@ void OpenXRAPI::end_frame() {
}
}
+float OpenXRAPI::get_display_refresh_rate() const {
+ OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
+ if (drrext) {
+ return drrext->get_refresh_rate();
+ }
+
+ return 0.0;
+}
+
+void OpenXRAPI::set_display_refresh_rate(float p_refresh_rate) {
+ OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
+ if (drrext != nullptr) {
+ drrext->set_refresh_rate(p_refresh_rate);
+ }
+}
+
+Array OpenXRAPI::get_available_display_refresh_rates() const {
+ OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
+ if (drrext != nullptr) {
+ return drrext->get_available_refresh_rates();
+ }
+
+ return Array();
+}
+
OpenXRAPI::OpenXRAPI() {
// OpenXRAPI is only constructed if OpenXR is enabled.
singleton = this;
@@ -1817,6 +1843,7 @@ OpenXRAPI::OpenXRAPI() {
register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension(this)));
register_extension_wrapper(memnew(OpenXRHandTrackingExtension(this)));
register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper(this)));
+ register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension(this)));
}
OpenXRAPI::~OpenXRAPI() {
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index bd69432dcb..5dce749351 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -84,8 +84,6 @@ private:
bool ext_vive_focus3_available = false;
bool ext_huawei_controller_available = false;
- bool is_path_supported(const String &p_path);
-
// composition layer providers
Vector<OpenXRCompositionLayerProvider *> composition_layer_providers;
@@ -302,6 +300,7 @@ public:
void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
bool xr_result(XrResult result, const char *format, Array args = Array()) const;
+ bool is_path_supported(const String &p_path);
static bool openxr_is_enabled(bool p_check_run_in_editor = true);
static OpenXRAPI *get_singleton();
@@ -336,6 +335,11 @@ public:
void post_draw_viewport(RID p_render_target);
void end_frame();
+ // Display refresh rate
+ float get_display_refresh_rate() const;
+ void set_display_refresh_rate(float p_refresh_rate);
+ Array get_available_display_refresh_rates() const;
+
// action map
String get_default_action_map_resource_name();
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 68414ae84e..bdf437b0b7 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -41,6 +41,13 @@ void OpenXRInterface::_bind_methods() {
ADD_SIGNAL(MethodInfo("session_focussed"));
ADD_SIGNAL(MethodInfo("session_visible"));
ADD_SIGNAL(MethodInfo("pose_recentered"));
+
+ // Display refresh rate
+ ClassDB::bind_method(D_METHOD("get_display_refresh_rate"), &OpenXRInterface::get_display_refresh_rate);
+ ClassDB::bind_method(D_METHOD("set_display_refresh_rate", "refresh_rate"), &OpenXRInterface::set_display_refresh_rate);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "display_refresh_rate"), "set_display_refresh_rate", "get_display_refresh_rate");
+
+ ClassDB::bind_method(D_METHOD("get_available_display_refresh_rates"), &OpenXRInterface::get_available_display_refresh_rates);
}
StringName OpenXRInterface::get_name() const {
@@ -147,24 +154,25 @@ void OpenXRInterface::_load_action_map() {
Ref<OpenXRAction> xr_action = actions[j];
PackedStringArray toplevel_paths = xr_action->get_toplevel_paths();
- Vector<Tracker *> trackers_new;
+ Vector<Tracker *> trackers_for_action;
for (int k = 0; k < toplevel_paths.size(); k++) {
- Tracker *tracker = find_tracker(toplevel_paths[k], true);
- if (tracker) {
- trackers_new.push_back(tracker);
+ // Only check for our tracker if our path is supported.
+ if (openxr_api->is_path_supported(toplevel_paths[k])) {
+ Tracker *tracker = find_tracker(toplevel_paths[k], true);
+ if (tracker) {
+ trackers_for_action.push_back(tracker);
+ }
}
}
- Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), trackers);
- if (action) {
- // we link our actions back to our trackers so we know which actions to check when we're processing our trackers
- for (int t = 0; t < trackers_new.size(); t++) {
- link_action_to_tracker(trackers_new[t], action);
+ // Only add our action if we have atleast one valid toplevel path
+ if (trackers_for_action.size() > 0) {
+ Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), trackers_for_action);
+ if (action) {
+ // add this to our map for creating our interaction profiles
+ xr_actions[xr_action] = action;
}
-
- // add this to our map for creating our interaction profiles
- xr_actions[xr_action] = action;
}
}
}
@@ -282,6 +290,13 @@ OpenXRInterface::Action *OpenXRInterface::create_action(ActionSet *p_action_set,
action->action_rid = openxr_api->action_create(p_action_set->action_set_rid, p_action_name, p_localized_name, p_action_type, tracker_rids);
p_action_set->actions.push_back(action);
+ // we link our actions back to our trackers so we know which actions to check when we're processing our trackers
+ for (int i = 0; i < p_trackers.size(); i++) {
+ if (p_trackers[i]->actions.find(action) == -1) {
+ p_trackers[i]->actions.push_back(action);
+ }
+ }
+
return action;
}
@@ -330,6 +345,8 @@ OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_tracker_
return nullptr;
}
+ ERR_FAIL_COND_V(!openxr_api->is_path_supported(p_tracker_name), nullptr);
+
// Create our RID
RID tracker_rid = openxr_api->tracker_create(p_tracker_name);
ERR_FAIL_COND_V(tracker_rid.is_null(), nullptr);
@@ -389,12 +406,6 @@ void OpenXRInterface::tracker_profile_changed(RID p_tracker, RID p_interaction_p
}
}
-void OpenXRInterface::link_action_to_tracker(Tracker *p_tracker, Action *p_action) {
- if (p_tracker->actions.find(p_action) == -1) {
- p_tracker->actions.push_back(p_action);
- }
-}
-
void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
ERR_FAIL_NULL(openxr_api);
ERR_FAIL_COND(p_tracker->positional_tracker.is_null());
@@ -447,9 +458,18 @@ void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
void OpenXRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
ERR_FAIL_NULL(openxr_api);
+
Action *action = find_action(p_action_name);
ERR_FAIL_NULL(action);
- Tracker *tracker = find_tracker(p_tracker_name);
+
+ // We need to map our tracker name to our OpenXR name for our inbuild names.
+ String tracker_name = p_tracker_name;
+ if (tracker_name == "left_hand") {
+ tracker_name = "/user/hand/left";
+ } else if (tracker_name == "right_hand") {
+ tracker_name = "/user/hand/right";
+ }
+ Tracker *tracker = find_tracker(tracker_name);
ERR_FAIL_NULL(tracker);
// TODO OpenXR does not support delay, so we may need to add support for that somehow...
@@ -571,6 +591,36 @@ bool OpenXRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
return false;
}
+float OpenXRInterface::get_display_refresh_rate() const {
+ if (openxr_api == nullptr) {
+ return 0.0;
+ } else if (!openxr_api->is_initialized()) {
+ return 0.0;
+ } else {
+ return openxr_api->get_display_refresh_rate();
+ }
+}
+
+void OpenXRInterface::set_display_refresh_rate(float p_refresh_rate) {
+ if (openxr_api == nullptr) {
+ return;
+ } else if (!openxr_api->is_initialized()) {
+ return;
+ } else {
+ openxr_api->set_display_refresh_rate(p_refresh_rate);
+ }
+}
+
+Array OpenXRInterface::get_available_display_refresh_rates() const {
+ if (openxr_api == nullptr) {
+ return Array();
+ } else if (!openxr_api->is_initialized()) {
+ return Array();
+ } else {
+ return openxr_api->get_available_display_refresh_rates();
+ }
+}
+
Size2 OpenXRInterface::get_render_target_size() {
if (openxr_api == nullptr) {
return Size2();
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index 72935b039c..454612346f 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -91,7 +91,6 @@ private:
void free_actions(ActionSet *p_action_set);
Tracker *find_tracker(const String &p_tracker_name, bool p_create = false);
- void link_action_to_tracker(Tracker *p_tracker, Action *p_action);
void handle_tracker(Tracker *p_tracker);
void free_trackers();
@@ -120,6 +119,10 @@ public:
virtual XRInterface::PlayAreaMode get_play_area_mode() const override;
virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
+ float get_display_refresh_rate() const;
+ void set_display_refresh_rate(float p_refresh_rate);
+ Array get_available_display_refresh_rates() const;
+
virtual Size2 get_render_target_size() override;
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 56404f796c..2abfc93722 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -4,7 +4,7 @@
Class for searching text for patterns using regular expressions.
</brief_description>
<description>
- A regular expression (or regex) is a compact language that can be used to recognise strings that follow a specific pattern, such as URLs, email addresses, complete sentences, etc. For instance, a regex of [code]ab[0-9][/code] would find any string that is [code]ab[/code] followed by any number from [code]0[/code] to [code]9[/code]. For a more in-depth look, you can easily find various tutorials and detailed explanations on the Internet.
+ A regular expression (or regex) is a compact language that can be used to recognise strings that follow a specific pattern, such as URLs, email addresses, complete sentences, etc. For example, a regex of [code]ab[0-9][/code] would find any string that is [code]ab[/code] followed by any number from [code]0[/code] to [code]9[/code]. For a more in-depth look, you can easily find various tutorials and detailed explanations on the Internet.
To begin, the RegEx object needs to be compiled with the search pattern using [method compile] before it can be used.
[codeblock]
var regex = RegEx.new()
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index eb398f77c7..0929d3a2b0 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -810,12 +810,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
ret.y = 0x7fffffff;
ret.x = 0;
+ const int *ct_offsets_ptr = ct.offsets.ptr();
for (int j = 0; j < ct.texture_w - mw; j++) {
int max_y = 0;
-
for (int k = j; k < j + mw; k++) {
- int y = ct.offsets[k];
+ int y = ct_offsets_ptr[k];
if (y > max_y) {
max_y = y;
}
@@ -1393,7 +1393,10 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
int error = 0;
if (!ft_library) {
error = FT_Init_FreeType(&ft_library);
- ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ if (error != 0) {
+ memdelete(fd);
+ ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
}
memset(&fd->stream, 0, sizeof(FT_StreamRec));
@@ -1422,6 +1425,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
}
@@ -1835,6 +1839,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
FT_Done_MM_Var(ft_library, amaster);
}
#else
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
#endif
} else {
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 13c997c981..4a46e17868 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -233,12 +233,13 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
ret.y = 0x7fffffff;
ret.x = 0;
+ const int *ct_offsets_ptr = ct.offsets.ptr();
for (int j = 0; j < ct.texture_w - mw; j++) {
int max_y = 0;
for (int k = j; k < j + mw; k++) {
- int y = ct.offsets[k];
+ int y = ct_offsets_ptr[k];
if (y > max_y) {
max_y = y;
}
@@ -818,7 +819,10 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
int error = 0;
if (!ft_library) {
error = FT_Init_FreeType(&ft_library);
- ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ if (error != 0) {
+ memdelete(fd);
+ ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
}
memset(&fd->stream, 0, sizeof(FT_StreamRec));
@@ -847,6 +851,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
}
@@ -945,6 +950,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
FT_Done_MM_Var(ft_library, amaster);
}
#else
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
#endif
}
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index 4930b178ec..84e022182e 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -320,7 +320,9 @@ void WSLPeer::_do_client_handshake() {
}
tcp->poll();
- if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
+ if (tcp->get_status() == StreamPeerTCP::STATUS_CONNECTING) {
+ return; // Keep connecting.
+ } else if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
close(-1); // Failed to connect.
return;
}
@@ -511,7 +513,7 @@ Error WSLPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509Ce
resolver.start(host, port);
resolver.try_next_candidate(tcp);
- if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTING && !resolver.has_more_candidates()) {
+ if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTING && tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED && !resolver.has_more_candidates()) {
_clear();
return FAILED;
}
diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h
index 34d068be3e..d8d5bd99cc 100644
--- a/modules/webxr/godot_webxr.h
+++ b/modules/webxr/godot_webxr.h
@@ -65,7 +65,7 @@ extern int godot_webxr_get_view_count();
extern int *godot_webxr_get_render_target_size();
extern float *godot_webxr_get_transform_for_eye(int p_eye);
extern float *godot_webxr_get_projection_for_eye(int p_eye);
-extern void godot_webxr_commit_for_eye(int p_eye, unsigned int p_destination_fbo);
+extern void godot_webxr_commit(unsigned int p_texture);
extern void godot_webxr_sample_controller_data();
extern int godot_webxr_get_controller_count();
diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js
index 9b75796ee5..c476a54c59 100644
--- a/modules/webxr/native/library_godot_webxr.js
+++ b/modules/webxr/native/library_godot_webxr.js
@@ -337,20 +337,18 @@ const GodotWebXR = {
return buf;
},
- godot_webxr_commit_for_eye__proxy: 'sync',
- godot_webxr_commit_for_eye__sig: 'vii',
- godot_webxr_commit_for_eye: function (p_eye, p_destination_fbo) {
+ godot_webxr_commit__proxy: 'sync',
+ godot_webxr_commit__sig: 'vi',
+ godot_webxr_commit: function (p_texture) {
if (!GodotWebXR.session || !GodotWebXR.pose) {
return;
}
- const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
const glLayer = GodotWebXR.session.renderState.baseLayer;
- const view = GodotWebXR.pose.views[view_index];
- const viewport = glLayer.getViewport(view);
+ const views = GodotWebXR.pose.views;
const gl = GodotWebXR.gl;
- const framebuffer = GL.framebuffers[p_destination_fbo];
+ const texture = GL.textures[p_texture];
const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
const orig_read_framebuffer = gl.getParameter(gl.READ_FRAMEBUFFER_BINDING);
@@ -359,14 +357,27 @@ const GodotWebXR = {
// Copy from Godot render target into framebuffer from WebXR.
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
- gl.bindFramebuffer(gl.READ_FRAMEBUFFER, framebuffer);
- gl.readBuffer(gl.COLOR_ATTACHMENT0);
- gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer);
-
- // Flip Y upside down on destination.
- gl.blitFramebuffer(0, 0, viewport.width, viewport.height,
- viewport.x, viewport.height, viewport.width, viewport.y,
- gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ for (let i = 0; i < views.length; i++) {
+ const viewport = glLayer.getViewport(views[i]);
+
+ const read_fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, read_fbo);
+ if (views.length > 1) {
+ gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture, 0, i);
+ } else {
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ }
+ gl.readBuffer(gl.COLOR_ATTACHMENT0);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer);
+
+ // Flip Y upside down on destination.
+ gl.blitFramebuffer(0, 0, viewport.width, viewport.height,
+ viewport.x, viewport.y + viewport.height, viewport.x + viewport.width, viewport.y,
+ gl.COLOR_BUFFER_BIT, gl.NEAREST);
+
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+ gl.deleteFramebuffer(read_fbo);
+ }
// Restore state.
gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer);
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 6b671c1660..f6ed9f027e 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -415,8 +415,7 @@ Vector<BlitToScreen> WebXRInterfaceJS::post_draw_viewport(RID p_render_target, c
GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
- // @todo Support multiple eyes!
- godot_webxr_commit_for_eye(1, rt->fbo);
+ godot_webxr_commit(rt->color);
return blit_to_screen;
};
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index 454bcd2eda..c0b098cd7f 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -118,7 +118,7 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycod
Input::get_singleton()->parse_input_event(ev);
}
-void AndroidInputHandler::_parse_all_touch(bool p_pressed) {
+void AndroidInputHandler::_parse_all_touch(bool p_pressed, bool p_double_tap) {
if (touch.size()) {
//end all if exist
for (int i = 0; i < touch.size(); i++) {
@@ -127,17 +127,18 @@ void AndroidInputHandler::_parse_all_touch(bool p_pressed) {
ev->set_index(touch[i].id);
ev->set_pressed(p_pressed);
ev->set_position(touch[i].pos);
+ ev->set_double_tap(p_double_tap);
Input::get_singleton()->parse_input_event(ev);
}
}
}
void AndroidInputHandler::_release_all_touch() {
- _parse_all_touch(false);
+ _parse_all_touch(false, false);
touch.clear();
}
-void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points) {
+void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap) {
switch (p_event) {
case AMOTION_EVENT_ACTION_DOWN: { //gesture begin
// Release any remaining touches or mouse event
@@ -151,7 +152,7 @@ void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const
}
//send touch
- _parse_all_touch(true);
+ _parse_all_touch(true, p_double_tap);
} break;
case AMOTION_EVENT_ACTION_MOVE: { //motion
diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h
index 88490f0407..4da8a910c0 100644
--- a/platform/android/android_input_handler.h
+++ b/platform/android/android_input_handler.h
@@ -87,13 +87,13 @@ private:
void _release_mouse_event_info(bool p_source_mouse_relative = false);
- void _parse_all_touch(bool p_pressed);
+ void _parse_all_touch(bool p_pressed, bool p_double_tap);
void _release_all_touch();
public:
void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative);
- void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points);
+ void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap);
void process_magnify(Point2 p_pos, float p_factor);
void process_pan(Point2 p_pos, Vector2 p_delta);
void process_joy_event(JoypadEvent p_event);
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 317f111202..6426f95b42 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -2901,20 +2901,22 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
_load_image_data(splash_bg_color_image, data);
}
- for (int i = 0; i < icon_densities_count; ++i) {
- if (main_image.is_valid() && !main_image->is_empty()) {
- if (file == launcher_icons[i].export_path) {
- _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
+ if (file.ends_with(".png") && file.contains("mipmap")) {
+ for (int i = 0; i < icon_densities_count; ++i) {
+ if (main_image.is_valid() && !main_image->is_empty()) {
+ if (file == launcher_icons[i].export_path) {
+ _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
+ }
}
- }
- if (foreground.is_valid() && !foreground->is_empty()) {
- if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
- _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
+ if (foreground.is_valid() && !foreground->is_empty()) {
+ if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
+ _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
+ }
}
- }
- if (background.is_valid() && !background->is_empty()) {
- if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
- _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
+ if (background.is_valid() && !background->is_empty()) {
+ if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
+ _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
+ }
}
}
}
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index 05608883d7..5a91e5ce32 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -276,6 +276,11 @@ task generateDevTemplate {
finalizedBy 'zipCustomBuild'
}
+task clean(type: Delete) {
+ dependsOn 'cleanGodotEditor'
+ dependsOn 'cleanGodotTemplates'
+}
+
/**
* Clean the generated editor artifacts.
*/
@@ -292,8 +297,6 @@ task cleanGodotEditor(type: Delete) {
// Delete the Godot editor apks in the Godot bin directory
delete("$binDir/android_editor.apk")
delete("$binDir/android_editor_dev.apk")
-
- finalizedBy getTasksByName("clean", true)
}
/**
@@ -321,5 +324,8 @@ task cleanGodotTemplates(type: Delete) {
delete("$binDir/godot-lib.template_debug.dev.aar")
delete("$binDir/godot-lib.template_release.aar")
- finalizedBy getTasksByName("clean", true)
+ // Cover deletion for the libs using the previous naming scheme
+ delete("$binDir/godot-lib.debug.aar")
+ delete("$binDir/godot-lib.dev.aar")
+ delete("$binDir/godot-lib.release.aar")
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 26aad867b1..33896ecb95 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -110,7 +110,7 @@ public class GodotLib {
/**
* Forward touch events.
*/
- public static native void dispatchTouchEvent(int event, int pointer, int pointerCount, float[] positions);
+ public static native void dispatchTouchEvent(int event, int pointer, int pointerCount, float[] positions, boolean doubleTap);
/**
* Dispatch mouse events
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
index 9715c31fc1..a7a57621de 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -55,18 +55,15 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
*/
var panningAndScalingEnabled = false
- private var doubleTapInProgress = false
+ private var nextDownIsDoubleTap = false
private var dragInProgress = false
private var scaleInProgress = false
private var contextClickInProgress = false
private var pointerCaptureInProgress = false
override fun onDown(event: MotionEvent): Boolean {
- // Don't send / register a down event while we're in the middle of a double-tap
- if (!doubleTapInProgress) {
- // Send the down event
- GodotInputHandler.handleMotionEvent(event)
- }
+ GodotInputHandler.handleMotionEvent(event.source, MotionEvent.ACTION_DOWN, event.buttonState, event.x, event.y, nextDownIsDoubleTap)
+ nextDownIsDoubleTap = false
return true
}
@@ -209,24 +206,14 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
override fun onDoubleTapEvent(event: MotionEvent): Boolean {
if (event.actionMasked == MotionEvent.ACTION_UP) {
- doubleTapInProgress = false
+ nextDownIsDoubleTap = false
+ GodotInputHandler.handleMotionEvent(event)
}
return true
}
override fun onDoubleTap(event: MotionEvent): Boolean {
- doubleTapInProgress = true
- val x = event.x
- val y = event.y
- val buttonMask =
- if (GodotInputHandler.isMouseEvent(event)) {
- event.buttonState
- } else {
- MotionEvent.BUTTON_PRIMARY
- }
- GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_DOWN, buttonMask, x, y, true)
- GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, 0, x, y, false)
-
+ nextDownIsDoubleTap = true
return true
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index 03cb8034fa..d2f3c5aed2 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -438,15 +438,19 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) {
- return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0);
+ return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, false);
}
- static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY) {
+ static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, boolean doubleTap) {
+ return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0, doubleTap);
+ }
+
+ static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleTap) {
if (isMouseEvent(eventSource)) {
- return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, false, false);
+ return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleTap, false);
}
- return handleTouchEvent(eventAction, x, y);
+ return handleTouchEvent(eventAction, x, y, doubleTap);
}
static boolean handleMouseEvent(final MotionEvent event) {
@@ -468,10 +472,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false, false);
}
- static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, boolean doubleClick) {
- return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, doubleClick, false);
- }
-
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
switch (eventAction) {
case MotionEvent.ACTION_CANCEL:
@@ -508,14 +508,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
final int action = event.getActionMasked();
final int actionPointerId = event.getPointerId(event.getActionIndex());
- return handleTouchEvent(action, actionPointerId, pointerCount, positions);
+ return handleTouchEvent(action, actionPointerId, pointerCount, positions, false);
}
- static boolean handleTouchEvent(int eventAction, float x, float y) {
- return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y });
+ static boolean handleTouchEvent(int eventAction, float x, float y, boolean doubleTap) {
+ return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y }, doubleTap);
}
- static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions) {
+ static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions, boolean doubleTap) {
switch (eventAction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
@@ -523,7 +523,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN: {
- GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions);
+ GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions, doubleTap);
return true;
}
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 04b69d5b86..5bf550a2b8 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -265,7 +265,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JN
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position, jboolean p_double_tap) {
if (step.get() <= 0) {
return;
}
@@ -280,7 +280,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JN
points.push_back(tp);
}
- input_handler->process_touch_event(ev, pointer, points);
+ input_handler->process_touch_event(ev, pointer, points, p_double_tap);
}
// Called on the UI thread
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 09fed15690..f3f2646bfb 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -46,7 +46,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env,
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jboolean p_double_tap);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed);
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index d3a0f38463..cf0fae4997 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -235,6 +235,7 @@ void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed,
ev->set_index(p_idx);
ev->set_pressed(p_pressed);
ev->set_position(Vector2(p_x, p_y));
+ ev->set_double_tap(p_double_click);
perform_event(ev);
}
}
diff --git a/platform/ios/view_controller.mm b/platform/ios/view_controller.mm
index 43669d3f94..53c5d3d0b4 100644
--- a/platform/ios/view_controller.mm
+++ b/platform/ios/view_controller.mm
@@ -164,7 +164,11 @@
// MARK: Orientation
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
- return UIRectEdgeAll;
+ if (GLOBAL_GET("display/window/ios/suppress_ui_gesture")) {
+ return UIRectEdgeAll;
+ } else {
+ return UIRectEdgeNone;
+ }
}
- (BOOL)shouldAutorotate {
@@ -206,7 +210,11 @@
}
- (BOOL)prefersStatusBarHidden {
- return YES;
+ if (GLOBAL_GET("display/window/ios/hide_status_bar")) {
+ return YES;
+ } else {
+ return NO;
+ }
}
- (BOOL)prefersHomeIndicatorAutoHidden {
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index e78467beff..162db675b0 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -4435,10 +4435,21 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n"
- "Please update your drivers or if you have a very old or integrated GPU, upgrade it.\n"
- "If you have updated your graphics drivers recently, try rebooting.",
- "Unable to initialize Video driver");
+ if (p_rendering_driver == "vulkan") {
+ String executable_name = OS::get_singleton()->get_executable_path().get_file();
+ OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
+ "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'./" +
+ executable_name + " --rendering-driver opengl3'.\n "
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ } else {
+ OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
+ "Please try updating your GPU driver.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ }
}
return ds;
}
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index f4692abc92..c7f49870f2 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -3408,7 +3408,26 @@ void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) {
DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.", "Unable to initialize Video driver");
+ if (p_rendering_driver == "vulkan") {
+ String executable_command;
+ if (OS::get_singleton()->get_bundle_resource_dir() == OS::get_singleton()->get_executable_path().get_base_dir()) {
+ executable_command = vformat("%s --rendering-driver opengl3", OS::get_singleton()->get_executable_path());
+ } else {
+ executable_command = vformat("open %s --args --rendering-driver opengl3", OS::get_singleton()->get_bundle_resource_dir().path_join("../..").simplify_path());
+ }
+ OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
+ "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command: '" +
+ executable_command + "'.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ } else {
+ OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
+ "Please try updating your GPU driver.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ }
}
return ds;
}
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index ae8534f6ab..8ffb0abfdb 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -148,9 +148,11 @@ void OS_MacOS::alert(const String &p_alert, const String &p_title) {
NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
NSString *ns_alert = [NSString stringWithUTF8String:p_alert.utf8().get_data()];
+ NSTextField *text_field = [NSTextField labelWithString:ns_alert];
+ [text_field setAlignment:NSTextAlignmentCenter];
[window addButtonWithTitle:@"OK"];
[window setMessageText:ns_title];
- [window setInformativeText:ns_alert];
+ [window setAccessoryView:text_field];
[window setAlertStyle:NSAlertStyleWarning];
id key_window = [[NSApplication sharedApplication] keyWindow];
diff --git a/platform/web/SCsub b/platform/web/SCsub
index cb00fa9f5b..077024507a 100644
--- a/platform/web/SCsub
+++ b/platform/web/SCsub
@@ -35,6 +35,7 @@ sys_env.AddJSLibraries(
"js/libs/library_godot_os.js",
"js/libs/library_godot_runtime.js",
"js/libs/library_godot_input.js",
+ "js/libs/library_godot_webgl2.js",
]
)
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index f6a61b18e4..2ee1edd2b4 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -773,6 +773,9 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
webgl2_init_failed = true;
} else {
+ if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) {
+ // @todo Should we log this?
+ }
RasterizerGLES3::make_current();
}
}
diff --git a/platform/web/godot_webgl2.h b/platform/web/godot_webgl2.h
index 968b70f84b..ae6b23ae18 100644
--- a/platform/web/godot_webgl2.h
+++ b/platform/web/godot_webgl2.h
@@ -34,4 +34,21 @@
#include "GLES3/gl3.h"
#include "webgl/webgl2.h"
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
+#define GL_MAX_VIEWS_OVR 0x9631
+#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void godot_webgl2_glFramebufferTextureMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+
+#define glFramebufferTextureMultiviewOVR godot_webgl2_glFramebufferTextureMultiviewOVR
+
+#ifdef __cplusplus
+}
+#endif
+
#endif // GODOT_WEBGL2_H
diff --git a/platform/web/js/libs/library_godot_webgl2.js b/platform/web/js/libs/library_godot_webgl2.js
new file mode 100644
index 0000000000..365f712be7
--- /dev/null
+++ b/platform/web/js/libs/library_godot_webgl2.js
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* library_godot_webgl2.js */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+const GodotWebGL2 = {
+ $GodotWebGL2__deps: ['$GL', '$GodotRuntime'],
+ $GodotWebGL2: {},
+
+ godot_webgl2_glFramebufferTextureMultiviewOVR__deps: ['emscripten_webgl_get_current_context'],
+ godot_webgl2_glFramebufferTextureMultiviewOVR__proxy: 'sync',
+ godot_webgl2_glFramebufferTextureMultiviewOVR__sig: 'viiiiii',
+ godot_webgl2_glFramebufferTextureMultiviewOVR: function (target, attachment, texture, level, base_view_index, num_views) {
+ const context = GL.currentContext;
+ if (typeof context.multiviewExt === 'undefined') {
+ const ext = context.GLctx.getExtension('OVR_multiview2');
+ if (!ext) {
+ console.error('Trying to call glFramebufferTextureMultiviewOVR() without the OVR_multiview2 extension');
+ return;
+ }
+ context.multiviewExt = ext;
+ }
+ context.multiviewExt.framebufferTextureMultiviewOVR(target, attachment, GL.textures[texture], level, base_view_index, num_views);
+ },
+};
+
+autoAddDeps(GodotWebGL2, '$GodotWebGL2');
+mergeInto(LibraryManager.library, GodotWebGL2);
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 3b773685c3..43d7208501 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -3087,7 +3087,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
rect_changed = true;
}
#if defined(VULKAN_ENABLED)
- if (context_vulkan && window_created) {
+ if (context_vulkan && window.context_created) {
// Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed.
context_vulkan->window_resize(window_id, window.width, window.height);
}
@@ -3547,6 +3547,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
windows.erase(id);
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Vulkan Window.");
}
+ wd.context_created = true;
}
#endif
@@ -3921,9 +3922,21 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n"
- "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
- "Unable to initialize Video driver");
+ if (p_rendering_driver == "vulkan") {
+ String executable_name = OS::get_singleton()->get_executable_path().get_file();
+ OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
+ "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'./" +
+ executable_name + " --rendering-driver opengl3'.\n "
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ } else {
+ OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
+ "Please try updating your GPU driver.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ }
}
return ds;
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 6403b57d8d..53cde001ae 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -369,6 +369,7 @@ class DisplayServerWindows : public DisplayServer {
bool no_focus = false;
bool window_has_focus = false;
bool exclusive = false;
+ bool context_created = false;
// Used to transfer data between events using timer.
WPARAM saved_wparam;
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 80169bc80c..78b5199358 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -172,6 +172,7 @@ void Light2D::set_shadow_filter(ShadowFilter p_filter) {
ERR_FAIL_INDEX(p_filter, SHADOW_FILTER_MAX);
shadow_filter = p_filter;
RS::get_singleton()->canvas_light_set_shadow_filter(canvas_light, RS::CanvasLightShadowFilter(p_filter));
+ notify_property_list_changed();
}
Light2D::ShadowFilter Light2D::get_shadow_filter() const {
@@ -231,6 +232,10 @@ void Light2D::_validate_property(PropertyInfo &p_property) const {
if (!shadow && (p_property.name == "shadow_color" || p_property.name == "shadow_filter" || p_property.name == "shadow_filter_smooth" || p_property.name == "shadow_item_cull_mask")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
+
+ if (shadow && p_property.name == "shadow_filter_smooth" && shadow_filter == SHADOW_FILTER_NONE) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
void Light2D::_bind_methods() {
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 26627a4fca..e865806a7f 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1097,8 +1097,8 @@ void TileMap::_rendering_update_layer(int p_layer) {
rs->canvas_item_set_sort_children_by_y(ci, layers[p_layer].y_sort_enabled);
rs->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid());
rs->canvas_item_set_z_index(ci, layers[p_layer].z_index);
- rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter()));
- rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat()));
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
rs->canvas_item_set_light_mask(ci, get_light_mask());
}
@@ -1208,8 +1208,8 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
rs->canvas_item_set_z_as_relative_to_parent(ci, true);
rs->canvas_item_set_z_index(ci, tile_z_index);
- rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter()));
- rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat()));
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
q.canvas_items.push_back(ci);
@@ -2206,11 +2206,10 @@ void TileMap::set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPat
}
}
-TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints) {
+TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints, TileSet::TerrainsPattern p_current_pattern) {
if (!tile_set.is_valid()) {
return TileSet::TerrainsPattern();
}
-
// Returns all tiles compatible with the given constraints.
RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score;
RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set);
@@ -2221,28 +2220,41 @@ TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int
// Check the center bit constraint
TerrainConstraint terrain_constraint = TerrainConstraint(this, p_position, terrain_pattern.get_terrain());
RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint);
- if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
- score += in_set_constraint_element->get().get_priority();
+ if (in_set_constraint_element) {
+ if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
+ score += in_set_constraint_element->get().get_priority();
+ }
+ } else if (p_current_pattern.get_terrain() != terrain_pattern.get_terrain()) {
+ continue; // Ignore a pattern that cannot keep bits without constraints unmodified.
}
// Check the surrounding bits
+ bool invalid_pattern = false;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
// Check if the bit is compatible with the constraints.
TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit));
in_set_constraint_element = p_constraints.find(terrain_bit_constraint);
- if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
- score += in_set_constraint_element->get().get_priority();
+ if (in_set_constraint_element) {
+ if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
+ score += in_set_constraint_element->get().get_priority();
+ }
+ } else if (p_current_pattern.get_terrain_peering_bit(bit) != terrain_pattern.get_terrain_peering_bit(bit)) {
+ invalid_pattern = true; // Ignore a pattern that cannot keep bits without constraints unmodified.
+ break;
}
}
}
+ if (invalid_pattern) {
+ continue;
+ }
terrain_pattern_score[terrain_pattern] = score;
}
// Compute the minimum score
- TileSet::TerrainsPattern min_score_pattern;
+ TileSet::TerrainsPattern min_score_pattern = p_current_pattern;
int min_score = INT32_MAX;
for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) {
if (E.value < min_score) {
@@ -2274,7 +2286,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_added_p
return output;
}
-RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_cell_list, int p_terrain_set, bool p_ignore_empty_terrains) const {
+RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const {
if (!tile_set.is_valid()) {
return RBSet<TerrainConstraint>();
}
@@ -2284,8 +2296,8 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
// Build a set of dummy constraints to get the constrained points.
RBSet<TerrainConstraint> dummy_constraints;
- for (const Vector2i &E : p_cell_list) {
- for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over sides.
+ for (const Vector2i &E : p_painted) {
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits.
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
dummy_constraints.insert(TerrainConstraint(this, E, bit, -1));
@@ -2342,7 +2354,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
}
// Add the centers as constraints
- for (Vector2i E_coords : p_cell_list) {
+ for (Vector2i E_coords : p_painted) {
TileData *tile_data = nullptr;
TileMapCell cell = get_cell(p_layer, E_coords);
if (cell.source_id != TileSet::INVALID_SOURCE) {
@@ -2362,7 +2374,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
return constraints;
}
-HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) {
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) {
if (!tile_set.is_valid()) {
return HashMap<Vector2i, TileSet::TerrainsPattern>();
}
@@ -2378,7 +2390,20 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(co
const Vector2i &coords = p_to_replace[i];
// Select the best pattern for the given constraints
- TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints);
+ TileSet::TerrainsPattern current_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, coords);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ current_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints, current_pattern);
// Update the constraint set with the new ones
RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern);
@@ -2492,12 +2517,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
}
// Fills in the constraint list from existing tiles.
- for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2527,10 +2552,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
// Build list and set of tiles that can be modified (painted and their surroundings)
Vector<Vector2i> can_modify_list;
RBSet<Vector2i> can_modify_set;
+ RBSet<Vector2i> painted_set;
for (int i = p_path.size() - 1; i >= 0; i--) {
const Vector2i &coords = p_path[i];
can_modify_list.push_back(coords);
can_modify_set.insert(coords);
+ painted_set.insert(coords);
}
for (Vector2i coords : p_path) {
// Find the adequate neighbor
@@ -2563,12 +2590,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
}
// Fills in the constraint list from existing tiles.
- for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2580,10 +2607,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
// Build list and set of tiles that can be modified (painted and their surroundings).
Vector<Vector2i> can_modify_list;
RBSet<Vector2i> can_modify_set;
+ RBSet<Vector2i> painted_set;
for (int i = p_coords_array.size() - 1; i >= 0; i--) {
const Vector2i &coords = p_coords_array[i];
can_modify_list.push_back(coords);
can_modify_set.insert(coords);
+ painted_set.insert(coords);
}
for (Vector2i coords : p_coords_array) {
// Find the adequate neighbor
@@ -2613,12 +2642,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
}
// Fills in the constraint list from modified tiles border.
- for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2627,14 +2656,38 @@ void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cell
ERR_FAIL_INDEX(p_layer, (int)layers.size());
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
- Vector<Vector2i> vector_cells;
+ Vector<Vector2i> cells_vector;
+ HashSet<Vector2i> painted_set;
for (int i = 0; i < p_cells.size(); i++) {
- vector_cells.push_back(p_cells[i]);
- }
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, vector_cells, p_terrain_set, p_terrain, p_ignore_empty_terrains);
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
- set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ cells_vector.push_back(p_cells[i]);
+ painted_set.insert(p_cells[i]);
+ }
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, kv.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ if (in_map_terrain_pattern != kv.value) {
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ }
+ }
}
}
@@ -2644,13 +2697,38 @@ void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, i
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
Vector<Vector2i> vector_path;
+ HashSet<Vector2i> painted_set;
for (int i = 0; i < p_path.size(); i++) {
vector_path.push_back(p_path[i]);
+ painted_set.insert(p_path[i]);
}
+
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(p_layer, vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains);
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
- set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, kv.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ if (in_map_terrain_pattern != kv.value) {
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ }
+ }
}
}
@@ -3717,13 +3795,14 @@ void TileMap::set_use_parent_material(bool p_use_parent_material) {
}
void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
- // Set a default texture filter for the whole tilemap
+ // Set a default texture filter for the whole tilemap.
CanvasItem::set_texture_filter(p_texture_filter);
+ TextureFilter target_filter = get_texture_filter_in_tree();
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
TileMapQuadrant &q = F->value;
for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(p_texture_filter));
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(target_filter));
_make_quadrant_dirty(F);
}
}
@@ -3732,13 +3811,14 @@ void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
}
void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
- // Set a default texture repeat for the whole tilemap
+ // Set a default texture repeat for the whole tilemap.
CanvasItem::set_texture_repeat(p_texture_repeat);
+ TextureRepeat target_repeat = get_texture_repeat_in_tree();
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
TileMapQuadrant &q = F->value;
for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(p_texture_repeat));
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(target_repeat));
_make_quadrant_dirty(F);
}
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index d468675e91..7f3e241871 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -266,9 +266,9 @@ private:
void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
// Terrains.
- TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints);
+ TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints, TileSet::TerrainsPattern p_current_pattern);
RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const;
- RBSet<TerrainConstraint> _get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_on_map, int p_terrain_set, bool p_ignore_empty_terrains) const;
+ RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const;
// Set and get tiles from data arrays.
void _set_tile_data(int p_layer, const Vector<int> &p_data);
@@ -352,7 +352,7 @@ public:
void set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern);
// Terrains.
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed.
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed.
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed.
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 04f73a4cbd..457f634c34 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -71,8 +71,8 @@ public:
};
private:
- // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaterinon/Scale and Euler Rotation/Scale.
- // Transform and Quaterinon are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand).
+ // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaternion/Scale and Euler Rotation/Scale.
+ // Transform and Quaternion are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand).
// Euler needs to be kept separate because converting to Basis and back may result in a different vector (which is troublesome for users
// editing in the inspector, not only because of the numerical precision loss but because they expect these rotations to be consistent, or support
// "redundant" rotations for animation interpolation, like going from 0 to 720 degrees).
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index e93ad5ecbf..3868d1e42e 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -40,10 +40,6 @@ AABB VisualInstance3D::get_aabb() const {
return AABB();
}
-AABB VisualInstance3D::get_transformed_aabb() const {
- return get_global_transform().xform(get_aabb());
-}
-
void VisualInstance3D::_update_visibility() {
if (!is_inside_tree()) {
return;
@@ -121,8 +117,6 @@ void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer_mask_value", "layer_number", "value"), &VisualInstance3D::set_layer_mask_value);
ClassDB::bind_method(D_METHOD("get_layer_mask_value", "layer_number"), &VisualInstance3D::get_layer_mask_value);
- ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance3D::get_transformed_aabb);
-
GDVIRTUAL_BIND(_get_aabb);
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask");
}
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 4755545516..06a8c05faa 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -60,8 +60,6 @@ public:
RID get_instance() const;
virtual AABB get_aabb() const;
- virtual AABB get_transformed_aabb() const; // helper
-
void set_base(const RID &p_base);
RID get_base() const;
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index fe4ccbc7dc..f5d30c584f 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -363,7 +363,7 @@ void XRNode3D::_unbind_tracker() {
}
void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
- if (p_tracker_name == p_tracker_name) {
+ if (tracker_name == p_tracker_name) {
// just in case unref our current tracker
_unbind_tracker();
@@ -373,7 +373,7 @@ void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_t
}
void XRNode3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
- if (p_tracker_name == p_tracker_name) {
+ if (tracker_name == p_tracker_name) {
// unref our tracker, it's no longer available
_unbind_tracker();
}
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index a2c138c0b2..929bf27be6 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -1367,7 +1367,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
Ref<Image> img = r->get_texture()->get_image();
if (img.is_valid() && !img->is_empty()) {
- Vector2 ofs = mev->get_global_position() - r->get_visible_rect().get_position();
+ Vector2 ofs = mev->get_global_position();
Color c = img->get_pixel(ofs.x, ofs.y);
set_pick_color(c);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 565e450d60..2ec0a48278 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -1436,13 +1436,6 @@ Rect2 Control::get_screen_rect() const {
return r;
}
-Rect2 Control::get_window_rect() const {
- ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
- Rect2 gr = get_global_rect();
- gr.position += get_viewport()->get_visible_rect().position;
- return gr;
-}
-
Rect2 Control::get_anchorable_rect() const {
return Rect2(Point2(), get_size());
}
@@ -1564,7 +1557,7 @@ Size2 Control::get_minimum_size() const {
return Vector2();
}
-void Control::set_custom_minimum_size(const Size2i &p_custom) {
+void Control::set_custom_minimum_size(const Size2 &p_custom) {
if (p_custom == data.custom_minimum_size) {
return;
}
@@ -1572,7 +1565,7 @@ void Control::set_custom_minimum_size(const Size2i &p_custom) {
update_minimum_size();
}
-Size2i Control::get_custom_minimum_size() const {
+Size2 Control::get_custom_minimum_size() const {
return data.custom_minimum_size;
}
@@ -3175,7 +3168,7 @@ void Control::_bind_methods() {
ADD_GROUP("Layout", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index e526690cbe..72e870930d 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -201,7 +201,7 @@ private:
int h_size_flags = SIZE_FILL;
int v_size_flags = SIZE_FILL;
real_t expand = 1.0;
- Point2i custom_minimum_size;
+ Point2 custom_minimum_size;
// Input events and rendering.
@@ -445,7 +445,6 @@ public:
Rect2 get_rect() const;
Rect2 get_global_rect() const;
Rect2 get_screen_rect() const;
- Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the rendering server
Rect2 get_anchorable_rect() const override;
void set_scale(const Vector2 &p_scale);
@@ -463,8 +462,8 @@ public:
virtual Size2 get_minimum_size() const;
virtual Size2 get_combined_minimum_size() const;
- void set_custom_minimum_size(const Size2i &p_custom);
- Size2i get_custom_minimum_size() const;
+ void set_custom_minimum_size(const Size2 &p_custom);
+ Size2 get_custom_minimum_size() const;
// Container sizing.
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 193c6f1ce7..6899178885 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -338,7 +338,7 @@ void ScrollBar::_notification(int p_what) {
if (scrolling) {
if (get_value() != target_scroll) {
double target = target_scroll - get_value();
- double dist = sqrt(target * target);
+ double dist = abs(target);
double vel = ((target / dist) * 500) * get_physics_process_delta_time();
if (Math::abs(vel) >= dist) {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 4cd244306c..b1c2676bc1 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -464,7 +464,7 @@ void TextEdit::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (scrolling && get_v_scroll() != target_v_scroll) {
double target_y = target_v_scroll - get_v_scroll();
- double dist = sqrt(target_y * target_y);
+ double dist = abs(target_y);
// To ensure minimap is responsive override the speed setting.
double vel = ((target_y / dist) * ((minimap_clicked) ? 3000 : v_scroll_speed)) * get_physics_process_delta_time();
@@ -3863,7 +3863,7 @@ void TextEdit::undo() {
}
caret_pos_dirty = true;
}
- queue_redraw();
+ adjust_viewport_to_caret();
}
void TextEdit::redo() {
@@ -3915,7 +3915,7 @@ void TextEdit::redo() {
}
caret_pos_dirty = true;
}
- queue_redraw();
+ adjust_viewport_to_caret();
}
void TextEdit::clear_undo_history() {
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 05d86f77f2..1dc28d91c5 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -1092,7 +1092,7 @@ int CanvasItem::get_canvas_layer() const {
}
}
-void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+void CanvasItem::_refresh_texture_filter_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1107,6 +1107,14 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
} else {
texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
}
+}
+
+void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_filter_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
queue_redraw();
@@ -1133,7 +1141,7 @@ CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
return texture_filter;
}
-void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+void CanvasItem::_refresh_texture_repeat_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1148,6 +1156,14 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
} else {
texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
}
+}
+
+void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_repeat_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
queue_redraw();
if (p_propagate) {
@@ -1189,6 +1205,16 @@ CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
return texture_repeat;
}
+CanvasItem::TextureFilter CanvasItem::get_texture_filter_in_tree() {
+ _refresh_texture_filter_cache();
+ return (TextureFilter)texture_filter_cache;
+}
+
+CanvasItem::TextureRepeat CanvasItem::get_texture_repeat_in_tree() {
+ _refresh_texture_repeat_cache();
+ return (TextureRepeat)texture_repeat_cache;
+}
+
CanvasItem::CanvasItem() :
xform_change(this) {
canvas_item = RenderingServer::get_singleton()->canvas_item_create();
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index b80289fdb4..ca91fff9ea 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -121,7 +121,9 @@ private:
static CanvasItem *current_item_drawn;
friend class Viewport;
+ void _refresh_texture_repeat_cache();
void _update_texture_repeat_changed(bool p_propagate);
+ void _refresh_texture_filter_cache();
void _update_texture_filter_changed(bool p_propagate);
protected:
@@ -310,6 +312,9 @@ public:
virtual void set_texture_repeat(TextureRepeat p_texture_repeat);
TextureRepeat get_texture_repeat() const;
+ TextureFilter get_texture_filter_in_tree();
+ TextureRepeat get_texture_repeat_in_tree();
+
// Used by control nodes to retrieve the parent's anchorable area
virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index f66337a2f9..a2963eadd5 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -3729,6 +3729,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_global_canvas_transform", "xform"), &Viewport::set_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_global_canvas_transform"), &Viewport::get_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_final_transform"), &Viewport::get_final_transform);
+ ClassDB::bind_method(D_METHOD("get_screen_transform"), &Viewport::get_screen_transform);
ClassDB::bind_method(D_METHOD("get_visible_rect"), &Viewport::get_visible_rect);
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index fe43f345d4..61daf801e8 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -105,6 +105,7 @@ void Shape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("collide_and_get_contacts", "local_xform", "with_shape", "shape_xform"), &Shape2D::collide_and_get_contacts);
ClassDB::bind_method(D_METHOD("collide_with_motion_and_get_contacts", "local_xform", "local_motion", "with_shape", "shape_xform", "shape_motion"), &Shape2D::collide_with_motion_and_get_contacts);
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "color"), &Shape2D::draw);
+ ClassDB::bind_method(D_METHOD("get_rect"), &Shape2D::get_rect);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias");
}
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 3a2b0ed9cb..fbcf140925 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -122,7 +122,7 @@ void Texture2D::_bind_methods() {
GDVIRTUAL_BIND(_draw, "to_canvas_item", "pos", "modulate", "transpose")
GDVIRTUAL_BIND(_draw_rect, "to_canvas_item", "rect", "tile", "modulate", "transpose")
- GDVIRTUAL_BIND(_draw_rect_region, "tp_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv");
+ GDVIRTUAL_BIND(_draw_rect_region, "to_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv");
}
Texture2D::Texture2D() {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index e156679711..8f175e99a6 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -277,6 +277,9 @@ public:
bool operator<(const TerrainsPattern &p_terrains_pattern) const;
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
+ bool operator!=(const TerrainsPattern &p_terrains_pattern) const {
+ return !operator==(p_terrains_pattern);
+ };
void set_terrain(int p_terrain);
int get_terrain() const;
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index de13912b75..a4c958d402 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -7264,7 +7264,7 @@ String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualS
} else {
code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n";
}
- code += " __depth_world_pos.xyz /= __depth_world_pos.z;\n";
+ code += " __depth_world_pos.xyz /= __depth_world_pos.w;\n";
code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]);
return code;
diff --git a/servers/physics_3d/godot_body_3d.cpp b/servers/physics_3d/godot_body_3d.cpp
index cec233d95b..53f4ab86f9 100644
--- a/servers/physics_3d/godot_body_3d.cpp
+++ b/servers/physics_3d/godot_body_3d.cpp
@@ -118,7 +118,7 @@ void GodotBody3D::update_mass_properties() {
shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed();
Vector3 shape_origin = shape_transform.origin - center_of_mass_local;
- inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass;
+ inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass_new;
}
// Set the inertia to a valid value when there are no valid shapes.
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index f4a27144d9..550fe27e4c 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -2866,7 +2866,8 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
{
Transform3D to_cell = gi->voxel_gi_get_to_cell_xform(probe);
- Transform3D to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse();
+ Transform3D to_probe_xform = to_cell * transform.affine_inverse();
+
//update lights
for (uint32_t i = 0; i < light_count; i++) {
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 4a18c7c052..8593e6b265 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -655,20 +655,7 @@ void main() {
if (i >= light_count) {
break;
}
- uint light_base;
- if (i < 8) {
- if (i < 4) {
- light_base = draw_data.lights[0];
- } else {
- light_base = draw_data.lights[1];
- }
- } else {
- if (i < 12) {
- light_base = draw_data.lights[2];
- } else {
- light_base = draw_data.lights[3];
- }
- }
+ uint light_base = draw_data.lights[i >> 2];
light_base >>= (i & 3) * 8;
light_base &= 0xFF;
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index cf34caac28..cd1b421ce8 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -411,9 +411,13 @@ TEST_CASE("[String] Number to string") {
CHECK(String::num_real(3.141593) == "3.141593");
CHECK(String::num_real(3.141) == "3.141"); // No trailing zeros.
#ifdef REAL_T_IS_DOUBLE
+ CHECK_MESSAGE(String::num_real(123.456789) == "123.456789", "Prints the appropriate amount of digits for real_t = double.");
+ CHECK_MESSAGE(String::num_real(-123.456789) == "-123.456789", "Prints the appropriate amount of digits for real_t = double.");
CHECK_MESSAGE(String::num_real(Math_PI) == "3.14159265358979", "Prints the appropriate amount of digits for real_t = double.");
CHECK_MESSAGE(String::num_real(3.1415f) == "3.1414999961853", "Prints more digits of 32-bit float when real_t = double (ones that would be reliable for double) and no trailing zero.");
#else
+ CHECK_MESSAGE(String::num_real(123.456789) == "123.4568", "Prints the appropriate amount of digits for real_t = float.");
+ CHECK_MESSAGE(String::num_real(-123.456789) == "-123.4568", "Prints the appropriate amount of digits for real_t = float.");
CHECK_MESSAGE(String::num_real(Math_PI) == "3.141593", "Prints the appropriate amount of digits for real_t = float.");
CHECK_MESSAGE(String::num_real(3.1415f) == "3.1415", "Prints only reliable digits of 32-bit float when real_t = float.");
#endif // REAL_T_IS_DOUBLE
diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h
index 3a20ac123b..2ef0a3345f 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -3918,6 +3918,32 @@ TEST_CASE("[SceneTree][TextEdit] viewport") {
CHECK(text_edit->get_last_full_visible_line_wrap_index() == 0);
CHECK(text_edit->get_caret_wrap_index() == 0);
+ // Typing and undo / redo should adjust viewport
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+ text_edit->set_line_as_first_visible(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 5);
+
+ SEND_GUI_KEY_EVENT(text_edit, Key::A);
+ CHECK(text_edit->get_first_visible_line() == 0);
+
+ text_edit->set_line_as_first_visible(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 5);
+
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 0);
+
+ text_edit->set_line_as_first_visible(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 5);
+
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 0);
+
memdelete(text_edit);
}
diff --git a/thirdparty/glad/KHR/khrplatform.h b/thirdparty/glad/KHR/khrplatform.h
index dd22d92701..01646449ca 100644
--- a/thirdparty/glad/KHR/khrplatform.h
+++ b/thirdparty/glad/KHR/khrplatform.h
@@ -153,6 +153,20 @@ typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
+/*
+ * To support platform where unsigned long cannot be used interchangeably with
+ * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
+ * Ideally, we could just use (u)intptr_t everywhere, but this could result in
+ * ABI breakage if khronos_uintptr_t is changed from unsigned long to
+ * unsigned long long or similar (this results in different C++ name mangling).
+ * To avoid changes for existing platforms, we restrict usage of intptr_t to
+ * platforms where the size of a pointer is larger than the size of long.
+ */
+#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
+#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
+#define KHRONOS_USE_INTPTR_T
+#endif
+#endif
#elif defined(__VMS ) || defined(__sgi)
@@ -235,14 +249,21 @@ typedef unsigned short int khronos_uint16_t;
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
-#ifdef _WIN64
+#ifdef KHRONOS_USE_INTPTR_T
+typedef intptr_t khronos_intptr_t;
+typedef uintptr_t khronos_uintptr_t;
+#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
-typedef signed long long int khronos_ssize_t;
-typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
+#endif
+
+#if defined(_WIN64)
+typedef signed long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
diff --git a/thirdparty/glad/glad.c b/thirdparty/glad/glad.c
index dc1b8cb697..4b20178ef7 100644
--- a/thirdparty/glad/glad.c
+++ b/thirdparty/glad/glad.c
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.34 on Tue Nov 17 16:41:02 2020.
+ OpenGL loader generated by glad 0.1.36 on Sun Sep 4 15:50:32 2022.
Language/Generator: C/C++
Specification: gl
@@ -11,16 +11,18 @@
GL_ARB_framebuffer_object,
GL_EXT_framebuffer_blit,
GL_EXT_framebuffer_multisample,
- GL_EXT_framebuffer_object
+ GL_EXT_framebuffer_object,
+ GL_OVR_multiview,
+ GL_OVR_multiview2
Loader: True
Local files: False
Omit khrplatform: False
Reproducible: False
Commandline:
- --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object"
+ --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2"
Online:
- https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object
+ https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2
*/
#include <stdio.h>
@@ -1000,6 +1002,8 @@ int GLAD_GL_ARB_framebuffer_object = 0;
int GLAD_GL_EXT_framebuffer_blit = 0;
int GLAD_GL_EXT_framebuffer_multisample = 0;
int GLAD_GL_EXT_framebuffer_object = 0;
+int GLAD_GL_OVR_multiview = 0;
+int GLAD_GL_OVR_multiview2 = 0;
PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL;
PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL;
PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL;
@@ -1023,6 +1027,7 @@ PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT = NULL;
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL;
PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL;
+PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR = NULL;
static void load_GL_VERSION_1_0(GLADloadproc load) {
if(!GLAD_GL_VERSION_1_0) return;
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
@@ -1844,6 +1849,10 @@ static void load_GL_EXT_framebuffer_object(GLADloadproc load) {
glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)load("glGetFramebufferAttachmentParameterivEXT");
glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)load("glGenerateMipmapEXT");
}
+static void load_GL_OVR_multiview(GLADloadproc load) {
+ if(!GLAD_GL_OVR_multiview) return;
+ glad_glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)load("glFramebufferTextureMultiviewOVR");
+}
static int find_extensionsGL(void) {
if (!get_exts()) return 0;
GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output");
@@ -1851,6 +1860,8 @@ static int find_extensionsGL(void) {
GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit");
GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample");
GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object");
+ GLAD_GL_OVR_multiview = has_ext("GL_OVR_multiview");
+ GLAD_GL_OVR_multiview2 = has_ext("GL_OVR_multiview2");
free_exts();
return 1;
}
@@ -1934,6 +1945,7 @@ int gladLoadGLLoader(GLADloadproc load) {
load_GL_EXT_framebuffer_blit(load);
load_GL_EXT_framebuffer_multisample(load);
load_GL_EXT_framebuffer_object(load);
+ load_GL_OVR_multiview(load);
return GLVersion.major != 0 || GLVersion.minor != 0;
}
diff --git a/thirdparty/glad/glad/glad.h b/thirdparty/glad/glad/glad.h
index f211e6aa57..37d12e4ee2 100644
--- a/thirdparty/glad/glad/glad.h
+++ b/thirdparty/glad/glad/glad.h
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.34 on Tue Nov 17 16:41:02 2020.
+ OpenGL loader generated by glad 0.1.36 on Sun Sep 4 15:50:32 2022.
Language/Generator: C/C++
Specification: gl
@@ -11,16 +11,18 @@
GL_ARB_framebuffer_object,
GL_EXT_framebuffer_blit,
GL_EXT_framebuffer_multisample,
- GL_EXT_framebuffer_object
+ GL_EXT_framebuffer_object,
+ GL_OVR_multiview,
+ GL_OVR_multiview2
Loader: True
Local files: False
Omit khrplatform: False
Reproducible: False
Commandline:
- --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object"
+ --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2"
Online:
- https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object
+ https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2
*/
@@ -3687,6 +3689,10 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
+#define GL_MAX_VIEWS_OVR 0x9631
+#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
#ifndef GL_ARB_debug_output
#define GL_ARB_debug_output 1
GLAPI int GLAD_GL_ARB_debug_output;
@@ -3776,6 +3782,17 @@ typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC)(GLenum target);
GLAPI PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT;
#define glGenerateMipmapEXT glad_glGenerateMipmapEXT
#endif
+#ifndef GL_OVR_multiview
+#define GL_OVR_multiview 1
+GLAPI int GLAD_GL_OVR_multiview;
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+GLAPI PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR;
+#define glFramebufferTextureMultiviewOVR glad_glFramebufferTextureMultiviewOVR
+#endif
+#ifndef GL_OVR_multiview2
+#define GL_OVR_multiview2 1
+GLAPI int GLAD_GL_OVR_multiview2;
+#endif
#ifdef __cplusplus
}