diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 9b326cb43e90..e832faaca477 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -56,7 +56,7 @@ jobs:
- name: Class reference schema checks
run: |
- xmllint --noout --schema doc/class.xsd doc/classes/*.xml modules/*/doc_classes/*.xml platform/*/doc_classes/*.xml
+ xmllint --quiet --noout --schema doc/class.xsd doc/classes/*.xml modules/*/doc_classes/*.xml platform/*/doc_classes/*.xml
- name: Run C compiler on `gdextension_interface.h`
run: |
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index a8cdb6f737f5..30cdd789a448 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1563,6 +1563,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/block_size_kb", PROPERTY_HINT_RANGE, "4,2048,1,or_greater"), 256);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/max_size_mb", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 128);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_upload_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_download_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
GLOBAL_DEF_RST(PropertyInfo(Variant::BOOL, "rendering/rendering_device/pipeline_cache/enable"), true);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/rendering_device/pipeline_cache/save_chunk_size_mb", PROPERTY_HINT_RANGE, "0.000001,64.0,0.001,or_greater"), 3.0);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/vulkan/max_descriptors_per_pool", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index 57ac241eb229..cb43c196cda2 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -46,8 +46,8 @@
[gdscript]
var box = AABB(Vector3(5, 0, 5), Vector3(-20, -10, -5))
var absolute = box.abs()
- print(absolute.position) # Prints (-15, -10, 0)
- print(absolute.size) # Prints (20, 10, 5)
+ print(absolute.position) # Prints (-15.0, -10.0, 0.0)
+ print(absolute.size) # Prints (20.0, 10.0, 5.0)
[/gdscript]
[csharp]
var box = new Aabb(new Vector3(5, 0, 5), new Vector3(-20, -10, -5));
@@ -96,12 +96,12 @@
var box = AABB(Vector3(0, 0, 0), Vector3(5, 2, 5))
box = box.expand(Vector3(10, 0, 0))
- print(box.position) # Prints (0, 0, 0)
- print(box.size) # Prints (10, 2, 5)
+ print(box.position) # Prints (0.0, 0.0, 0.0)
+ print(box.size) # Prints (10.0, 2.0, 5.0)
box = box.expand(Vector3(-5, 0, 5))
- print(box.position) # Prints (-5, 0, 0)
- print(box.size) # Prints (15, 2, 5)
+ print(box.position) # Prints (-5.0, 0.0, 0.0)
+ print(box.size) # Prints (15.0, 2.0, 5.0)
[/gdscript]
[csharp]
var box = new Aabb(new Vector3(0, 0, 0), new Vector3(5, 2, 5));
@@ -138,15 +138,15 @@
[gdscript]
var box = AABB(Vector3(0, 0, 0), Vector3(2, 4, 8))
- print(box.get_longest_axis()) # Prints (0, 0, 1)
+ print(box.get_longest_axis()) # Prints (0.0, 0.0, 1.0)
print(box.get_longest_axis_index()) # Prints 2
- print(box.get_longest_axis_size()) # Prints 8
+ print(box.get_longest_axis_size()) # Prints 8.0
[/gdscript]
[csharp]
var box = new Aabb(new Vector3(0, 0, 0), new Vector3(2, 4, 8));
GD.Print(box.GetLongestAxis()); // Prints (0, 0, 1)
- GD.Print(box.GetLongestAxisIndex()); // Prints 2
+ GD.Print(box.GetLongestAxisIndex()); // Prints Z
GD.Print(box.GetLongestAxisSize()); // Prints 8
[/csharp]
[/codeblocks]
@@ -175,15 +175,15 @@
[gdscript]
var box = AABB(Vector3(0, 0, 0), Vector3(2, 4, 8))
- print(box.get_shortest_axis()) # Prints (1, 0, 0)
+ print(box.get_shortest_axis()) # Prints (1.0, 0.0, 0.0)
print(box.get_shortest_axis_index()) # Prints 0
- print(box.get_shortest_axis_size()) # Prints 2
+ print(box.get_shortest_axis_size()) # Prints 2.0
[/gdscript]
[csharp]
var box = new Aabb(new Vector3(0, 0, 0), new Vector3(2, 4, 8));
GD.Print(box.GetShortestAxis()); // Prints (1, 0, 0)
- GD.Print(box.GetShortestAxisIndex()); // Prints 0
+ GD.Print(box.GetShortestAxisIndex()); // Prints X
GD.Print(box.GetShortestAxisSize()); // Prints 2
[/csharp]
[/codeblocks]
@@ -225,12 +225,12 @@
[codeblocks]
[gdscript]
var a = AABB(Vector3(4, 4, 4), Vector3(8, 8, 8)).grow(4)
- print(a.position) # Prints (0, 0, 0)
- print(a.size) # Prints (16, 16, 16)
+ print(a.position) # Prints (0.0, 0.0, 0.0)
+ print(a.size) # Prints (16.0, 16.0, 16.0)
var b = AABB(Vector3(0, 0, 0), Vector3(8, 4, 2)).grow(2)
- print(b.position) # Prints (-2, -2, -2)
- print(b.size) # Prints (12, 8, 6)
+ print(b.position) # Prints (-2.0, -2.0, -2.0)
+ print(b.size) # Prints (12.0, 8.0, 6.0)
[/gdscript]
[csharp]
var a = new Aabb(new Vector3(4, 4, 4), new Vector3(8, 8, 8)).Grow(4);
@@ -275,8 +275,8 @@
var box2 = AABB(Vector3(2, 0, 2), Vector3(8, 4, 4))
var intersection = box1.intersection(box2)
- print(intersection.position) # Prints (2, 0, 2)
- print(intersection.size) # Prints (3, 2, 4)
+ print(intersection.position) # Prints (2.0, 0.0, 2.0)
+ print(intersection.size) # Prints (3.0, 2.0, 4.0)
[/gdscript]
[csharp]
var box1 = new Aabb(new Vector3(0, 0, 0), new Vector3(5, 2, 8));
diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml
index 8e1972af116e..ac37a18a420c 100644
--- a/doc/classes/AStarGrid2D.xml
+++ b/doc/classes/AStarGrid2D.xml
@@ -12,8 +12,8 @@
astar_grid.region = Rect2i(0, 0, 32, 32)
astar_grid.cell_size = Vector2(16, 16)
astar_grid.update()
- print(astar_grid.get_id_path(Vector2i(0, 0), Vector2i(3, 4))) # prints (0, 0), (1, 1), (2, 2), (3, 3), (3, 4)
- print(astar_grid.get_point_path(Vector2i(0, 0), Vector2i(3, 4))) # prints (0, 0), (16, 16), (32, 32), (48, 48), (48, 64)
+ print(astar_grid.get_id_path(Vector2i(0, 0), Vector2i(3, 4))) # Prints [(0, 0), (1, 1), (2, 2), (3, 3), (3, 4)]
+ print(astar_grid.get_point_path(Vector2i(0, 0), Vector2i(3, 4))) # Prints [(0, 0), (16, 16), (32, 32), (48, 48), (48, 64)]
[/gdscript]
[csharp]
AStarGrid2D astarGrid = new AStarGrid2D();
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index 1b7dbf7c41fb..983e8fc98f5d 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -183,17 +183,17 @@
public override void _Ready()
{
- // Prints true (3/3 elements evaluate to true).
+ // Prints True (3/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array>int< { 6, 10, 6 }.All(GreaterThan5));
- // Prints false (1/3 elements evaluate to true).
+ // Prints False (1/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array>int< { 4, 10, 4 }.All(GreaterThan5));
- // Prints false (0/3 elements evaluate to true).
+ // Prints False (0/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array>int< { 4, 4, 4 }.All(GreaterThan5));
- // Prints true (0/0 elements evaluate to true).
+ // Prints True (0/0 elements evaluate to true).
GD.Print(new Godot.Collections.Array>int< { }.All(GreaterThan5));
// Same as the first line above, but using a lambda function.
- GD.Print(new Godot.Collections.Array>int< { 6, 10, 6 }.All(element => element > 5)); // Prints true
+ GD.Print(new Godot.Collections.Array>int< { 6, 10, 6 }.All(element => element > 5)); // Prints True
}
[/csharp]
[/codeblocks]
@@ -462,10 +462,10 @@
[csharp]
var arr = new Godot.Collections.Array { "inside", 7 };
// By C# convention, this method is renamed to `Contains`.
- GD.Print(arr.Contains("inside")); // Prints true
- GD.Print(arr.Contains("outside")); // Prints false
- GD.Print(arr.Contains(7)); // Prints true
- GD.Print(arr.Contains("7")); // Prints false
+ GD.Print(arr.Contains("inside")); // Prints True
+ GD.Print(arr.Contains("outside")); // Prints False
+ GD.Print(arr.Contains(7)); // Prints True
+ GD.Print(arr.Contains("7")); // Prints False
[/csharp]
[/codeblocks]
In GDScript, this is equivalent to the [code]in[/code] operator:
diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml
index d11e070d89b3..52e99512813d 100644
--- a/doc/classes/AudioStream.xml
+++ b/doc/classes/AudioStream.xml
@@ -13,6 +13,12 @@
https://godotengine.org/asset-library/asset/2762
+
+
+
+ Override this method to return the bar beats of this stream.
+
+
@@ -45,6 +51,12 @@
Override this method to customize the name assigned to this audio stream. Unused by the engine.
+
+
+
+ Override this method to return [code]true[/code] if this stream has a loop.
+
+
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index b8823cf18858..81f63addd4a5 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -91,7 +91,7 @@
# Creates a Basis whose z axis points down.
var my_basis = Basis.from_euler(Vector3(TAU / 4, 0, 0))
- print(my_basis.z) # Prints (0, -1, 0)
+ print(my_basis.z) # Prints (0.0, -1.0, 0.0)
[/gdscript]
[csharp]
// Creates a Basis whose z axis points down.
@@ -112,9 +112,9 @@
[gdscript]
var my_basis = Basis.from_scale(Vector3(2, 4, 8))
- print(my_basis.x) # Prints (2, 0, 0)
- print(my_basis.y) # Prints (0, 4, 0)
- print(my_basis.z) # Prints (0, 0, 8)
+ print(my_basis.x) # Prints (2.0, 0.0, 0.0)
+ print(my_basis.y) # Prints (0.0, 4.0, 0.0)
+ print(my_basis.z) # Prints (0.0, 0.0, 8.0)
[/gdscript]
[csharp]
var myBasis = Basis.FromScale(new Vector3(2.0f, 4.0f, 8.0f));
@@ -163,7 +163,7 @@
my_basis = my_basis.rotated(Vector3.UP, TAU / 2)
my_basis = my_basis.rotated(Vector3.RIGHT, TAU / 4)
- print(my_basis.get_scale()) # Prints (2, 4, 8)
+ print(my_basis.get_scale()) # Prints (2.0, 4.0, 8.0)
[/gdscript]
[csharp]
var myBasis = new Basis(
@@ -285,9 +285,9 @@
)
my_basis = my_basis.scaled(Vector3(0, 2, -2))
- print(my_basis.x) # Prints (0, 2, -2)
- print(my_basis.y) # Prints (0, 4, -4)
- print(my_basis.z) # Prints (0, 6, -6)
+ print(my_basis.x) # Prints (0.0, 2.0, -2.0)
+ print(my_basis.y) # Prints (0.0, 4.0, -4.0)
+ print(my_basis.z) # Prints (0.0, 6.0, -6.0)
[/gdscript]
[csharp]
var myBasis = new Basis(
@@ -360,9 +360,9 @@
)
my_basis = my_basis.transposed()
- print(my_basis.x) # Prints (1, 4, 7)
- print(my_basis.y) # Prints (2, 5, 8)
- print(my_basis.z) # Prints (3, 6, 9)
+ print(my_basis.x) # Prints (1.0, 4.0, 7.0)
+ print(my_basis.y) # Prints (2.0, 5.0, 8.0)
+ print(my_basis.z) # Prints (3.0, 6.0, 9.0)
[/gdscript]
[csharp]
var myBasis = new Basis(
@@ -454,7 +454,7 @@
[gdscript]
# Basis that swaps the X/Z axes and doubles the scale.
var my_basis = Basis(Vector3(0, 2, 0), Vector3(2, 0, 0), Vector3(0, 0, 2))
- print(my_basis * Vector3(1, 2, 3)) # Prints (4, 2, 6)
+ print(my_basis * Vector3(1, 2, 3)) # Prints (4.0, 2.0, 6.0)
[/gdscript]
[csharp]
// Basis that swaps the X/Z axes and doubles the scale.
diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml
index 5b3f86c9f57a..5103134f657f 100644
--- a/doc/classes/Button.xml
+++ b/doc/classes/Button.xml
@@ -47,7 +47,7 @@
If set to something other than [constant TextServer.AUTOWRAP_OFF], the text gets wrapped inside the node's bounding rectangle.
- When this property is enabled, text that is too large to fit the button is clipped, when disabled the Button will always be wide enough to hold the text.
+ If [code]true[/code], text that is too large to fit the button is clipped horizontally. If [code]false[/code], the button will always be wide enough to hold the text. The text is not vertically clipped, and the button's height is not affected by this property.
When enabled, the button's icon will expand/shrink to fit the button's size while keeping its aspect. See also [theme_item icon_max_width].
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index cf3c3e06fd51..d5978a42f6da 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -13,7 +13,7 @@
func test():
var callable = Callable(self, "print_args")
callable.call("hello", "world") # Prints "hello world ".
- callable.call(Vector2.UP, 42, callable) # Prints "(0, -1) 42 Node(node.gd)::print_args".
+ callable.call(Vector2.UP, 42, callable) # Prints "(0.0, -1.0) 42 Node(node.gd)::print_args".
callable.call("invalid") # Invalid call, should have at least 2 arguments.
[/gdscript]
[csharp]
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index 5c9b22fe4a1c..2e02de54a8eb 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -281,9 +281,9 @@
{ 210, default },
};
- GD.Print(myDict.ContainsKey("Godot")); // Prints true
- GD.Print(myDict.ContainsKey(210)); // Prints true
- GD.Print(myDict.ContainsKey(4)); // Prints false
+ GD.Print(myDict.ContainsKey("Godot")); // Prints True
+ GD.Print(myDict.ContainsKey(210)); // Prints True
+ GD.Print(myDict.ContainsKey(4)); // Prints False
[/csharp]
[/codeblocks]
In GDScript, this is equivalent to the [code]in[/code] operator:
@@ -321,7 +321,7 @@
var dict2 = new Godot.Collections.Dictionary{{"A", 10}, {"B", 2}};
// Godot.Collections.Dictionary has no Hash() method. Use GD.Hash() instead.
- GD.Print(GD.Hash(dict1) == GD.Hash(dict2)); // Prints true
+ GD.Print(GD.Hash(dict1) == GD.Hash(dict2)); // Prints True
[/csharp]
[/codeblocks]
[b]Note:[/b] Dictionaries with the same entries but in a different order will not have the same hash.
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index 3ae375393077..9b0879a794cb 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -209,10 +209,10 @@
print(Engine.has_singleton("Unknown")) # Prints false
[/gdscript]
[csharp]
- GD.Print(Engine.HasSingleton("OS")); // Prints true
- GD.Print(Engine.HasSingleton("Engine")); // Prints true
- GD.Print(Engine.HasSingleton("AudioServer")); // Prints true
- GD.Print(Engine.HasSingleton("Unknown")); // Prints false
+ GD.Print(Engine.HasSingleton("OS")); // Prints True
+ GD.Print(Engine.HasSingleton("Engine")); // Prints True
+ GD.Print(Engine.HasSingleton("AudioServer")); // Prints True
+ GD.Print(Engine.HasSingleton("Unknown")); // Prints False
[/csharp]
[/codeblocks]
[b]Note:[/b] Global singletons are not the same as autoloaded nodes, which are configurable in the project settings.
diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml
index 71e6cf93ae25..c86861fd130b 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -201,13 +201,13 @@
var polygon = PackedVector2Array([Vector2(0, 0), Vector2(100, 0), Vector2(100, 100), Vector2(0, 100)])
var offset = Vector2(50, 50)
polygon = Transform2D(0, offset) * polygon
- print(polygon) # prints [(50, 50), (150, 50), (150, 150), (50, 150)]
+ print(polygon) # Prints [(50.0, 50.0), (150.0, 50.0), (150.0, 150.0), (50.0, 150.0)]
[/gdscript]
[csharp]
var polygon = new Vector2[] { new Vector2(0, 0), new Vector2(100, 0), new Vector2(100, 100), new Vector2(0, 100) };
var offset = new Vector2(50, 50);
polygon = new Transform2D(0, offset) * polygon;
- GD.Print((Variant)polygon); // prints [(50, 50), (150, 50), (150, 150), (50, 150)]
+ GD.Print((Variant)polygon); // Prints [(50, 50), (150, 50), (150, 150), (50, 150)]
[/csharp]
[/codeblocks]
diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml
index 2d88876d2448..c6512e487971 100644
--- a/doc/classes/MainLoop.xml
+++ b/doc/classes/MainLoop.xml
@@ -78,6 +78,7 @@
Called each physics frame with the time since the last physics frame as argument ([param delta], in seconds). Equivalent to [method Node._physics_process].
If implemented, the method must return a boolean value. [code]true[/code] ends the main loop, while [code]false[/code] lets it proceed to the next frame.
+ [b]Note:[/b] [param delta] will be larger than expected if running at a framerate lower than [member Engine.physics_ticks_per_second] / [member Engine.max_physics_steps_per_frame] FPS. This is done to avoid "spiral of death" scenarios where performance would plummet due to an ever-increasing number of physics steps per frame. This behavior affects both [method _process] and [method _physics_process]. As a result, avoid using [param delta] for time measurements in real-world seconds. Use the [Time] singleton's methods for this purpose instead, such as [method Time.get_ticks_usec].
@@ -86,6 +87,7 @@
Called each process (idle) frame with the time since the last process frame as argument (in seconds). Equivalent to [method Node._process].
If implemented, the method must return a boolean value. [code]true[/code] ends the main loop, while [code]false[/code] lets it proceed to the next frame.
+ [b]Note:[/b] [param delta] will be larger than expected if running at a framerate lower than [member Engine.physics_ticks_per_second] / [member Engine.max_physics_steps_per_frame] FPS. This is done to avoid "spiral of death" scenarios where performance would plummet due to an ever-increasing number of physics steps per frame. This behavior affects both [method _process] and [method _physics_process]. As a result, avoid using [param delta] for time measurements in real-world seconds. Use the [Time] singleton's methods for this purpose instead, such as [method Time.get_ticks_usec].
diff --git a/doc/classes/NavigationPathQueryParameters2D.xml b/doc/classes/NavigationPathQueryParameters2D.xml
index ce0a00bc83bb..1f9c064f930b 100644
--- a/doc/classes/NavigationPathQueryParameters2D.xml
+++ b/doc/classes/NavigationPathQueryParameters2D.xml
@@ -49,6 +49,9 @@
Centers every path position in the middle of the traveled navigation mesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center.
+
+ Applies no postprocessing and returns the raw path corridor as found by the pathfinding algorithm.
+
Don't include any additional metadata about the returned path.
diff --git a/doc/classes/NavigationPathQueryParameters3D.xml b/doc/classes/NavigationPathQueryParameters3D.xml
index fcd913f73b59..a4c622d080d6 100644
--- a/doc/classes/NavigationPathQueryParameters3D.xml
+++ b/doc/classes/NavigationPathQueryParameters3D.xml
@@ -49,6 +49,9 @@
Centers every path position in the middle of the traveled navigation mesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center.
+
+ Applies no postprocessing and returns the raw path corridor as found by the pathfinding algorithm.
+
Don't include any additional metadata about the returned path.
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 5c19a6b355db..d1fac97b93e7 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -533,7 +533,7 @@
Returns all navigation obstacle [RID]s that are currently assigned to the requested navigation [param map].
-
+
@@ -754,12 +754,13 @@
[b]Performance:[/b] While convenient, reading data arrays from [Mesh] resources can affect the frame rate negatively. The data needs to be received from the GPU, stalling the [RenderingServer] in the process. For performance prefer the use of e.g. collision shapes or creating the data arrays entirely in code.
-
+
+
- Queries a path in a given navigation map. Start and target position and other parameters are defined through [NavigationPathQueryParameters2D]. Updates the provided [NavigationPathQueryResult2D] result object with the path among other results requested by the query.
+ Queries a path in a given navigation map. Start and target position and other parameters are defined through [NavigationPathQueryParameters2D]. Updates the provided [NavigationPathQueryResult2D] result object with the path among other results requested by the query. After the process is finished the optional [param callback] will be called.
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 66a286758bca..ab65f3f74376 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -605,7 +605,7 @@
Returns all navigation obstacle [RID]s that are currently assigned to the requested navigation [param map].
-
+
@@ -887,12 +887,13 @@
[b]Performance:[/b] While convenient, reading data arrays from [Mesh] resources can affect the frame rate negatively. The data needs to be received from the GPU, stalling the [RenderingServer] in the process. For performance prefer the use of e.g. collision shapes or creating the data arrays entirely in code.
-
+
+
- Queries a path in a given navigation map. Start and target position and other parameters are defined through [NavigationPathQueryParameters3D]. Updates the provided [NavigationPathQueryResult3D] result object with the path among other results requested by the query.
+ Queries a path in a given navigation map. Start and target position and other parameters are defined through [NavigationPathQueryParameters3D]. Updates the provided [NavigationPathQueryResult3D] result object with the path among other results requested by the query. After the process is finished the optional [param callback] will be called.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 1e12d619e22f..ff2a440e59bd 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -71,11 +71,12 @@
- Called during the physics processing step of the main loop. Physics processing means that the frame rate is synced to the physics, i.e. the [param delta] variable should be constant. [param delta] is in seconds.
+ Called during the physics processing step of the main loop. Physics processing means that the frame rate is synced to the physics, i.e. the [param delta] parameter will [i]generally[/i] be constant (see exceptions below). [param delta] is in seconds.
It is only called if physics processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_physics_process].
Processing happens in order of [member process_physics_priority], lower priority values are called first. Nodes with the same priority are processed in tree order, or top to bottom as seen in the editor (also known as pre-order traversal).
Corresponds to the [constant NOTIFICATION_PHYSICS_PROCESS] notification in [method Object._notification].
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
+ [b]Note:[/b] [param delta] will be larger than expected if running at a framerate lower than [member Engine.physics_ticks_per_second] / [member Engine.max_physics_steps_per_frame] FPS. This is done to avoid "spiral of death" scenarios where performance would plummet due to an ever-increasing number of physics steps per frame. This behavior affects both [method _process] and [method _physics_process]. As a result, avoid using [param delta] for time measurements in real-world seconds. Use the [Time] singleton's methods for this purpose instead, such as [method Time.get_ticks_usec].
@@ -87,6 +88,7 @@
Processing happens in order of [member process_priority], lower priority values are called first. Nodes with the same priority are processed in tree order, or top to bottom as seen in the editor (also known as pre-order traversal).
Corresponds to the [constant NOTIFICATION_PROCESS] notification in [method Object._notification].
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
+ [b]Note:[/b] [param delta] will be larger than expected if running at a framerate lower than [member Engine.physics_ticks_per_second] / [member Engine.max_physics_steps_per_frame] FPS. This is done to avoid "spiral of death" scenarios where performance would plummet due to an ever-increasing number of physics steps per frame. This behavior affects both [method _process] and [method _physics_process]. As a result, avoid using [param delta] for time measurements in real-world seconds. Use the [Time] singleton's methods for this purpose instead, such as [method Time.get_ticks_usec].
@@ -492,12 +494,14 @@
Returns the time elapsed (in seconds) since the last physics callback. This value is identical to [method _physics_process]'s [code]delta[/code] parameter, and is often consistent at run-time, unless [member Engine.physics_ticks_per_second] is changed. See also [constant NOTIFICATION_PHYSICS_PROCESS].
+ [b]Note:[/b] The returned value will be larger than expected if running at a framerate lower than [member Engine.physics_ticks_per_second] / [member Engine.max_physics_steps_per_frame] FPS. This is done to avoid "spiral of death" scenarios where performance would plummet due to an ever-increasing number of physics steps per frame. This behavior affects both [method _process] and [method _physics_process]. As a result, avoid using [code]delta[/code] for time measurements in real-world seconds. Use the [Time] singleton's methods for this purpose instead, such as [method Time.get_ticks_usec].
Returns the time elapsed (in seconds) since the last process callback. This value is identical to [method _process]'s [code]delta[/code] parameter, and may vary from frame to frame. See also [constant NOTIFICATION_PROCESS].
+ [b]Note:[/b] The returned value will be larger than expected if running at a framerate lower than [member Engine.physics_ticks_per_second] / [member Engine.max_physics_steps_per_frame] FPS. This is done to avoid "spiral of death" scenarios where performance would plummet due to an ever-increasing number of physics steps per frame. This behavior affects both [method _process] and [method _physics_process]. As a result, avoid using [code]delta[/code] for time measurements in real-world seconds. Use the [Time] singleton's methods for this purpose instead, such as [method Time.get_ticks_usec].
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 69d613b7cccb..669c71778d2e 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -629,10 +629,10 @@
print(OS.is_keycode_unicode(KEY_ESCAPE)) # Prints false
[/gdscript]
[csharp]
- GD.Print(OS.IsKeycodeUnicode((long)Key.G)); // Prints true
- GD.Print(OS.IsKeycodeUnicode((long)Key.Kp4)); // Prints true
- GD.Print(OS.IsKeycodeUnicode((long)Key.Tab)); // Prints false
- GD.Print(OS.IsKeycodeUnicode((long)Key.Escape)); // Prints false
+ GD.Print(OS.IsKeycodeUnicode((long)Key.G)); // Prints True
+ GD.Print(OS.IsKeycodeUnicode((long)Key.Kp4)); // Prints True
+ GD.Print(OS.IsKeycodeUnicode((long)Key.Tab)); // Prints False
+ GD.Print(OS.IsKeycodeUnicode((long)Key.Escape)); // Prints False
[/csharp]
[/codeblocks]
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 73fd7e19439a..febc81dd81c8 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -987,12 +987,12 @@
[gdscript]
var node = Node2D.new()
node.set("global_scale", Vector2(8, 2.5))
- print(node.global_scale) # Prints (8, 2.5)
+ print(node.global_scale) # Prints (8.0, 2.5)
[/gdscript]
[csharp]
var node = new Node2D();
- node.Set(Node2D.PropertyName.GlobalScale, new Vector2(8, 2.5));
- GD.Print(node.GlobalScale); // Prints Vector2(8, 2.5)
+ node.Set(Node2D.PropertyName.GlobalScale, new Vector2(8, 2.5f));
+ GD.Print(node.GlobalScale); // Prints (8, 2.5)
[/csharp]
[/codeblocks]
[b]Note:[/b] In C#, [param property] must be in snake_case when referring to built-in Godot properties. Prefer using the names exposed in the [code]PropertyName[/code] class to avoid allocating a new [StringName] on each call.
@@ -1047,7 +1047,7 @@
var node = Node2D.new()
node.set_indexed("position", Vector2(42, 0))
node.set_indexed("position:y", -10)
- print(node.position) # Prints (42, -10)
+ print(node.position) # Prints (42.0, -10.0)
[/gdscript]
[csharp]
var node = new Node2D();
diff --git a/doc/classes/PolygonPathFinder.xml b/doc/classes/PolygonPathFinder.xml
index b70633883c8c..98734c3e9b05 100644
--- a/doc/classes/PolygonPathFinder.xml
+++ b/doc/classes/PolygonPathFinder.xml
@@ -62,8 +62,8 @@
};
var connections = new int[] { 0, 1, 1, 2, 2, 0 };
polygonPathFinder.Setup(points, connections);
- GD.Print(polygonPathFinder.IsPointInside(new Vector2(0.2f, 0.2f))); // Prints true
- GD.Print(polygonPathFinder.IsPointInside(new Vector2(1.0f, 1.0f))); // Prints false
+ GD.Print(polygonPathFinder.IsPointInside(new Vector2(0.2f, 0.2f))); // Prints True
+ GD.Print(polygonPathFinder.IsPointInside(new Vector2(1.0f, 1.0f))); // Prints False
[/csharp]
[/codeblocks]
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 0a16b159316c..76cddce3dddd 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -2162,6 +2162,9 @@
If enabled, and baking would potentially lead to an engine crash, the baking will be interrupted and an error message with explanation will be raised.
+
+ Maximum number of threads that can run pathfinding queries simultaneously on the same pathfinding graph, for example the same navigation map. Additional threads increase memory consumption and synchronization time due to the need for extra data copies prepared for each thread. A value of [code]-1[/code] means unlimited and the maximum available OS processor count is used. Defaults to [code]1[/code] when the OS does not support threads.
+
Maximum number of characters allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
@@ -2972,10 +2975,22 @@
Determines at which interval pipeline cache is saved to disk. The lower the value, the more often it is saved.
+ The size of a block allocated in the staging buffers. Staging buffers are the intermediate resources the engine uses to upload or download data to the GPU. This setting determines the max amount of data that can be transferred in a copy operation. Increasing this will result in faster data transfers at the cost of extra memory.
+ [b]Note:[/b] This property is only read when the project starts. There is currently no way to change this value at run-time.
+ The maximum amount of memory allowed to be used by staging buffers. If the amount of data being uploaded or downloaded exceeds this amount, the GPU will stall and wait for previous frames to finish.
+ [b]Note:[/b] This property is only read when the project starts. There is currently no way to change this value at run-time.
+
+
+ The region size in pixels used to download texture data from the GPU when using methods like [method RenderingDevice.texture_get_data_async].
+ [b]Note:[/b] This property's upper limit is controlled by [member rendering/rendering_device/staging_buffer/block_size_kb] and whether it's possible to allocate a single block of texture data with this region size in the format that is requested.
+ [b]Note:[/b] This property is only read when the project starts. There is currently no way to change this value at run-time.
+ The region size in pixels used to upload texture data from the GPU when using methods like [method RenderingDevice.texture_update].
+ [b]Note:[/b] This property's upper limit is controlled by [member rendering/rendering_device/staging_buffer/block_size_kb] and whether it's possible to allocate a single block of texture data with this region size in the format that is requested.
+ [b]Note:[/b] This property is only read when the project starts. There is currently no way to change this value at run-time.
The number of frames to track on the CPU side before stalling to wait for the GPU.
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 59ca06085f2f..b7f95587cda6 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -58,6 +58,27 @@
Returns a copy of the data of the specified [param buffer], optionally [param offset_bytes] and [param size_bytes] can be set to copy only a portion of the buffer.
+ [b]Note:[/b] This method will block the GPU from working until the data is retrieved. Refer to [method buffer_get_data_async] for an alternative that returns the data in more performant way.
+
+
+
+
+
+
+
+
+
+ Asynchronous version of [method buffer_get_data]. RenderingDevice will call [param callback] in a certain amount of frames with the data the buffer had at the time of the request.
+ [b]Note:[/b] At the moment, the delay corresponds to the amount of frames specified by [member ProjectSettings.rendering/rendering_device/vsync/frame_queue_size].
+ [b]Note:[/b] Downloading large buffers can have a prohibitive cost for real-time even when using the asynchronous method due to hardware bandwidth limitations. When dealing with large resources, you can adjust settings such as [member ProjectSettings.rendering/rendering_device/staging_buffer/block_size_kb] to improve the transfer speed at the cost of extra memory.
+ [codeblock]
+ func _buffer_get_data_callback(array):
+ value = array.decode_u32(0)
+
+ ...
+
+ rd.buffer_get_data_async(buffer, _buffer_get_data_callback)
+ [/codeblock]
@@ -928,6 +949,26 @@
Returns the [param texture] data for the specified [param layer] as raw binary data. For 2D textures (which only have one layer), [param layer] must be [code]0[/code].
[b]Note:[/b] [param texture] can't be retrieved while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to [constant FINAL_ACTION_CONTINUE]) to retrieve this texture. Otherwise, an error is printed and a empty [PackedByteArray] is returned.
[b]Note:[/b] [param texture] requires the [constant TEXTURE_USAGE_CAN_COPY_FROM_BIT] to be retrieved. Otherwise, an error is printed and a empty [PackedByteArray] is returned.
+ [b]Note:[/b] This method will block the GPU from working until the data is retrieved. Refer to [method texture_get_data_async] for an alternative that returns the data in more performant way.
+
+
+
+
+
+
+
+
+ Asynchronous version of [method texture_get_data]. RenderingDevice will call [param callback] in a certain amount of frames with the data the texture had at the time of the request.
+ [b]Note:[/b] At the moment, the delay corresponds to the amount of frames specified by [member ProjectSettings.rendering/rendering_device/vsync/frame_queue_size].
+ [b]Note:[/b] Downloading large textures can have a prohibitive cost for real-time even when using the asynchronous method due to hardware bandwidth limitations. When dealing with large resources, you can adjust settings such as [member ProjectSettings.rendering/rendering_device/staging_buffer/texture_download_region_size_px] and [member ProjectSettings.rendering/rendering_device/staging_buffer/block_size_kb] to improve the transfer speed at the cost of extra memory.
+ [codeblock]
+ func _texture_get_data_callback(array):
+ value = array.decode_u32(0)
+
+ ...
+
+ rd.texture_get_data_async(texture, 0, _texture_get_data_callback)
+ [/codeblock]
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 69441e0010c6..3f25b18191c1 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -139,8 +139,8 @@
print("I" in "team") # Prints false
[/gdscript]
[csharp]
- GD.Print("Node".Contains("de")); // Prints true
- GD.Print("team".Contains("I")); // Prints false
+ GD.Print("Node".Contains("de")); // Prints True
+ GD.Print("team".Contains("I")); // Prints False
[/csharp]
[/codeblocks]
If you need to know where [param what] is within the string, use [method find]. See also [method containsn].
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index e561ef54faa3..074d79833b4d 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -122,8 +122,8 @@
print("I" in "team") # Prints false
[/gdscript]
[csharp]
- GD.Print("Node".Contains("de")); // Prints true
- GD.Print("team".Contains("I")); // Prints false
+ GD.Print("Node".Contains("de")); // Prints True
+ GD.Print("team".Contains("I")); // Prints False
[/csharp]
[/codeblocks]
If you need to know where [param what] is within the string, use [method find]. See also [method containsn].
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index bdc908d3877f..c55b5f1c9072 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -116,7 +116,7 @@
# Rotating the Transform2D in any way preserves its scale.
my_transform = my_transform.rotated(TAU / 2)
- print(my_transform.get_scale()) # Prints (2, 4)
+ print(my_transform.get_scale()) # Prints (2.0, 4.0)
[/gdscript]
[csharp]
var myTransform = new Transform2D(
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index c03262bb33b1..e9ddf57355a5 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -213,9 +213,9 @@
Creates a unit [Vector2] rotated to the given [param angle] in radians. This is equivalent to doing [code]Vector2(cos(angle), sin(angle))[/code] or [code]Vector2.RIGHT.rotated(angle)[/code].
[codeblock]
- print(Vector2.from_angle(0)) # Prints (1, 0).
- print(Vector2(1, 0).angle()) # Prints 0, which is the angle used above.
- print(Vector2.from_angle(PI / 2)) # Prints (0, 1).
+ print(Vector2.from_angle(0)) # Prints (1.0, 0.0).
+ print(Vector2(1, 0).angle()) # Prints 0.0, which is the angle used above.
+ print(Vector2.from_angle(PI / 2)) # Prints (0.0, 1.0).
[/codeblock]
@@ -270,7 +270,7 @@
- Returns the vector with a maximum length by limiting its length to [param length].
+ Returns the vector with a maximum length by limiting its length to [param length]. If the vector is non-finite, the result is undefined.
@@ -477,7 +477,7 @@
Multiplies each component of the [Vector2] by the components of the given [Vector2].
[codeblock]
- print(Vector2(10, 20) * Vector2(3, 4)) # Prints "(30, 80)"
+ print(Vector2(10, 20) * Vector2(3, 4)) # Prints (30.0, 80.0)
[/codeblock]
@@ -501,7 +501,7 @@
Adds each component of the [Vector2] by the components of the given [Vector2].
[codeblock]
- print(Vector2(10, 20) + Vector2(3, 4)) # Prints "(13, 24)"
+ print(Vector2(10, 20) + Vector2(3, 4)) # Prints (13.0, 24.0)
[/codeblock]
@@ -511,7 +511,7 @@
Subtracts each component of the [Vector2] by the components of the given [Vector2].
[codeblock]
- print(Vector2(10, 20) - Vector2(3, 4)) # Prints "(7, 16)"
+ print(Vector2(10, 20) - Vector2(3, 4)) # Prints (7.0, 16.0)
[/codeblock]
@@ -521,7 +521,7 @@
Divides each component of the [Vector2] by the components of the given [Vector2].
[codeblock]
- print(Vector2(10, 20) / Vector2(2, 5)) # Prints "(5, 4)"
+ print(Vector2(10, 20) / Vector2(2, 5)) # Prints (5.0, 4.0)
[/codeblock]
diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml
index 53c7c92ca38a..74dfc3efe97a 100644
--- a/doc/classes/Vector2i.xml
+++ b/doc/classes/Vector2i.xml
@@ -215,7 +215,7 @@
Gets the remainder of each component of the [Vector2i] with the components of the given [Vector2i]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
- print(Vector2i(10, -20) % Vector2i(7, 8)) # Prints "(3, -4)"
+ print(Vector2i(10, -20) % Vector2i(7, 8)) # Prints (3, -4)
[/codeblock]
@@ -225,7 +225,7 @@
Gets the remainder of each component of the [Vector2i] with the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
- print(Vector2i(10, -20) % 7) # Prints "(3, -6)"
+ print(Vector2i(10, -20) % 7) # Prints (3, -6)
[/codeblock]
@@ -235,7 +235,7 @@
Multiplies each component of the [Vector2i] by the components of the given [Vector2i].
[codeblock]
- print(Vector2i(10, 20) * Vector2i(3, 4)) # Prints "(30, 80)"
+ print(Vector2i(10, 20) * Vector2i(3, 4)) # Prints (30, 80)
[/codeblock]
@@ -245,7 +245,7 @@
Multiplies each component of the [Vector2i] by the given [float]. Returns a [Vector2].
[codeblock]
- print(Vector2i(10, 15) * 0.9) # Prints "(9, 13.5)"
+ print(Vector2i(10, 15) * 0.9) # Prints (9.0, 13.5)
[/codeblock]
@@ -262,7 +262,7 @@
Adds each component of the [Vector2i] by the components of the given [Vector2i].
[codeblock]
- print(Vector2i(10, 20) + Vector2i(3, 4)) # Prints "(13, 24)"
+ print(Vector2i(10, 20) + Vector2i(3, 4)) # Prints (13, 24)
[/codeblock]
@@ -272,7 +272,7 @@
Subtracts each component of the [Vector2i] by the components of the given [Vector2i].
[codeblock]
- print(Vector2i(10, 20) - Vector2i(3, 4)) # Prints "(7, 16)"
+ print(Vector2i(10, 20) - Vector2i(3, 4)) # Prints (7, 16)
[/codeblock]
@@ -282,7 +282,7 @@
Divides each component of the [Vector2i] by the components of the given [Vector2i].
[codeblock]
- print(Vector2i(10, 20) / Vector2i(2, 5)) # Prints "(5, 4)"
+ print(Vector2i(10, 20) / Vector2i(2, 5)) # Prints (5, 4)
[/codeblock]
@@ -292,7 +292,7 @@
Divides each component of the [Vector2i] by the given [float]. Returns a [Vector2].
[codeblock]
- print(Vector2i(10, 20) / 2.9) # Prints "(5, 10)"
+ print(Vector2i(10, 20) / 2.9) # Prints (5.0, 10.0)
[/codeblock]
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 4ab3140eb633..dd86c4b2874d 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -239,7 +239,7 @@
- Returns the vector with a maximum length by limiting its length to [param length].
+ Returns the vector with a maximum length by limiting its length to [param length]. If the vector is non-finite, the result is undefined.
@@ -518,7 +518,7 @@
Multiplies each component of the [Vector3] by the components of the given [Vector3].
[codeblock]
- print(Vector3(10, 20, 30) * Vector3(3, 4, 5)) # Prints "(30, 80, 150)"
+ print(Vector3(10, 20, 30) * Vector3(3, 4, 5)) # Prints (30.0, 80.0, 150.0)
[/codeblock]
@@ -542,7 +542,7 @@
Adds each component of the [Vector3] by the components of the given [Vector3].
[codeblock]
- print(Vector3(10, 20, 30) + Vector3(3, 4, 5)) # Prints "(13, 24, 35)"
+ print(Vector3(10, 20, 30) + Vector3(3, 4, 5)) # Prints (13.0, 24.0, 35.0)
[/codeblock]
@@ -552,7 +552,7 @@
Subtracts each component of the [Vector3] by the components of the given [Vector3].
[codeblock]
- print(Vector3(10, 20, 30) - Vector3(3, 4, 5)) # Prints "(7, 16, 25)"
+ print(Vector3(10, 20, 30) - Vector3(3, 4, 5)) # Prints (7.0, 16.0, 25.0)
[/codeblock]
@@ -562,7 +562,7 @@
Divides each component of the [Vector3] by the components of the given [Vector3].
[codeblock]
- print(Vector3(10, 20, 30) / Vector3(2, 5, 3)) # Prints "(5, 4, 10)"
+ print(Vector3(10, 20, 30) / Vector3(2, 5, 3)) # Prints (5.0, 4.0, 10.0)
[/codeblock]
diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml
index 7fe469aec075..64c2137b7d83 100644
--- a/doc/classes/Vector3i.xml
+++ b/doc/classes/Vector3i.xml
@@ -222,7 +222,7 @@
Gets the remainder of each component of the [Vector3i] with the components of the given [Vector3i]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
- print(Vector3i(10, -20, 30) % Vector3i(7, 8, 9)) # Prints "(3, -4, 3)"
+ print(Vector3i(10, -20, 30) % Vector3i(7, 8, 9)) # Prints (3, -4, 3)
[/codeblock]
@@ -232,7 +232,7 @@
Gets the remainder of each component of the [Vector3i] with the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
- print(Vector3i(10, -20, 30) % 7) # Prints "(3, -6, 2)"
+ print(Vector3i(10, -20, 30) % 7) # Prints (3, -6, 2)
[/codeblock]
@@ -242,7 +242,7 @@
Multiplies each component of the [Vector3i] by the components of the given [Vector3i].
[codeblock]
- print(Vector3i(10, 20, 30) * Vector3i(3, 4, 5)) # Prints "(30, 80, 150)"
+ print(Vector3i(10, 20, 30) * Vector3i(3, 4, 5)) # Prints (30, 80, 150)
[/codeblock]
@@ -252,7 +252,7 @@
Multiplies each component of the [Vector3i] by the given [float]. Returns a [Vector3].
[codeblock]
- print(Vector3i(10, 15, 20) * 0.9) # Prints "(9, 13.5, 18)"
+ print(Vector3i(10, 15, 20) * 0.9) # Prints (9.0, 13.5, 18.0)
[/codeblock]
@@ -269,7 +269,7 @@
Adds each component of the [Vector3i] by the components of the given [Vector3i].
[codeblock]
- print(Vector3i(10, 20, 30) + Vector3i(3, 4, 5)) # Prints "(13, 24, 35)"
+ print(Vector3i(10, 20, 30) + Vector3i(3, 4, 5)) # Prints (13, 24, 35)
[/codeblock]
@@ -279,7 +279,7 @@
Subtracts each component of the [Vector3i] by the components of the given [Vector3i].
[codeblock]
- print(Vector3i(10, 20, 30) - Vector3i(3, 4, 5)) # Prints "(7, 16, 25)"
+ print(Vector3i(10, 20, 30) - Vector3i(3, 4, 5)) # Prints (7, 16, 25)
[/codeblock]
@@ -289,7 +289,7 @@
Divides each component of the [Vector3i] by the components of the given [Vector3i].
[codeblock]
- print(Vector3i(10, 20, 30) / Vector3i(2, 5, 3)) # Prints "(5, 4, 10)"
+ print(Vector3i(10, 20, 30) / Vector3i(2, 5, 3)) # Prints (5, 4, 10)
[/codeblock]
@@ -299,7 +299,7 @@
Divides each component of the [Vector3i] by the given [float]. Returns a [Vector3].
[codeblock]
- print(Vector3i(10, 20, 30) / 2.9) # Prints "(5, 10, 15)"
+ print(Vector3i(10, 20, 30) / 2.9) # Prints (5.0, 10.0, 15.0)
[/codeblock]
diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml
index 8fa17b57e6cc..45780a1aedcb 100644
--- a/doc/classes/Vector4.xml
+++ b/doc/classes/Vector4.xml
@@ -333,7 +333,7 @@
Multiplies each component of the [Vector4] by the components of the given [Vector4].
[codeblock]
- print(Vector4(10, 20, 30, 40) * Vector4(3, 4, 5, 6)) # Prints "(30, 80, 150, 240)"
+ print(Vector4(10, 20, 30, 40) * Vector4(3, 4, 5, 6)) # Prints (30.0, 80.0, 150.0, 240.0)
[/codeblock]
@@ -343,7 +343,7 @@
Multiplies each component of the [Vector4] by the given [float].
[codeblock]
- print(Vector4(10, 20, 30, 40) * 2) # Prints "(20, 40, 60, 80)"
+ print(Vector4(10, 20, 30, 40) * 2) # Prints (20.0, 40.0, 60.0, 80.0)
[/codeblock]
@@ -360,7 +360,7 @@
Adds each component of the [Vector4] by the components of the given [Vector4].
[codeblock]
- print(Vector4(10, 20, 30, 40) + Vector4(3, 4, 5, 6)) # Prints "(13, 24, 35, 46)"
+ print(Vector4(10, 20, 30, 40) + Vector4(3, 4, 5, 6)) # Prints (13.0, 24.0, 35.0, 46.0)
[/codeblock]
@@ -370,7 +370,7 @@
Subtracts each component of the [Vector4] by the components of the given [Vector4].
[codeblock]
- print(Vector4(10, 20, 30, 40) - Vector4(3, 4, 5, 6)) # Prints "(7, 16, 25, 34)"
+ print(Vector4(10, 20, 30, 40) - Vector4(3, 4, 5, 6)) # Prints (7.0, 16.0, 25.0, 34.0)
[/codeblock]
@@ -380,7 +380,7 @@
Divides each component of the [Vector4] by the components of the given [Vector4].
[codeblock]
- print(Vector4(10, 20, 30, 40) / Vector4(2, 5, 3, 4)) # Prints "(5, 4, 10, 10)"
+ print(Vector4(10, 20, 30, 40) / Vector4(2, 5, 3, 4)) # Prints (5.0, 4.0, 10.0, 10.0)
[/codeblock]
@@ -390,7 +390,7 @@
Divides each component of the [Vector4] by the given [float].
[codeblock]
- print(Vector4(10, 20, 30, 40) / 2 # Prints "(5, 10, 15, 20)"
+ print(Vector4(10, 20, 30, 40) / 2 # Prints (5.0, 10.0, 15.0, 20.0)
[/codeblock]
diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml
index e1d65eb1b557..6c46f82a3bbb 100644
--- a/doc/classes/Vector4i.xml
+++ b/doc/classes/Vector4i.xml
@@ -208,7 +208,7 @@
Gets the remainder of each component of the [Vector4i] with the components of the given [Vector4i]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
- print(Vector4i(10, -20, 30, -40) % Vector4i(7, 8, 9, 10)) # Prints "(3, -4, 3, 0)"
+ print(Vector4i(10, -20, 30, -40) % Vector4i(7, 8, 9, 10)) # Prints (3, -4, 3, 0)
[/codeblock]
@@ -218,7 +218,7 @@
Gets the remainder of each component of the [Vector4i] with the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
- print(Vector4i(10, -20, 30, -40) % 7) # Prints "(3, -6, 2, -5)"
+ print(Vector4i(10, -20, 30, -40) % 7) # Prints (3, -6, 2, -5)
[/codeblock]
@@ -228,7 +228,7 @@
Multiplies each component of the [Vector4i] by the components of the given [Vector4i].
[codeblock]
- print(Vector4i(10, 20, 30, 40) * Vector4i(3, 4, 5, 6)) # Prints "(30, 80, 150, 240)"
+ print(Vector4i(10, 20, 30, 40) * Vector4i(3, 4, 5, 6)) # Prints (30, 80, 150, 240)
[/codeblock]
@@ -239,7 +239,7 @@
Multiplies each component of the [Vector4i] by the given [float].
Returns a Vector4 value due to floating-point operations.
[codeblock]
- print(Vector4i(10, 20, 30, 40) * 2) # Prints "(20, 40, 60, 80)"
+ print(Vector4i(10, 20, 30, 40) * 2) # Prints (20.0, 40.0, 60.0, 80.0)
[/codeblock]
@@ -256,7 +256,7 @@
Adds each component of the [Vector4i] by the components of the given [Vector4i].
[codeblock]
- print(Vector4i(10, 20, 30, 40) + Vector4i(3, 4, 5, 6)) # Prints "(13, 24, 35, 46)"
+ print(Vector4i(10, 20, 30, 40) + Vector4i(3, 4, 5, 6)) # Prints (13, 24, 35, 46)
[/codeblock]
@@ -266,7 +266,7 @@
Subtracts each component of the [Vector4i] by the components of the given [Vector4i].
[codeblock]
- print(Vector4i(10, 20, 30, 40) - Vector4i(3, 4, 5, 6)) # Prints "(7, 16, 25, 34)"
+ print(Vector4i(10, 20, 30, 40) - Vector4i(3, 4, 5, 6)) # Prints (7, 16, 25, 34)
[/codeblock]
@@ -276,7 +276,7 @@
Divides each component of the [Vector4i] by the components of the given [Vector4i].
[codeblock]
- print(Vector4i(10, 20, 30, 40) / Vector4i(2, 5, 3, 4)) # Prints "(5, 4, 10, 10)"
+ print(Vector4i(10, 20, 30, 40) / Vector4i(2, 5, 3, 4)) # Prints (5, 4, 10, 10)
[/codeblock]
@@ -287,7 +287,7 @@
Divides each component of the [Vector4i] by the given [float].
Returns a Vector4 value due to floating-point operations.
[codeblock]
- print(Vector4i(10, 20, 30, 40) / 2 # Prints "(5, 10, 15, 20)"
+ print(Vector4i(10, 20, 30, 40) / 2 # Prints (5.0, 10.0, 15.0, 20.0)
[/codeblock]
diff --git a/doc/classes/float.xml b/doc/classes/float.xml
index 56f78bdc8acc..96ac9a804973 100644
--- a/doc/classes/float.xml
+++ b/doc/classes/float.xml
@@ -97,7 +97,7 @@
Multiplies each component of the [Vector2i] by the given [float]. Returns a [Vector2].
[codeblock]
- print(0.9 * Vector2i(10, 15)) # Prints "(9, 13.5)"
+ print(0.9 * Vector2i(10, 15)) # Prints (9.0, 13.5)
[/codeblock]
@@ -114,7 +114,7 @@
Multiplies each component of the [Vector3i] by the given [float]. Returns a [Vector3].
[codeblock]
- print(0.9 * Vector3i(10, 15, 20)) # Prints "(9, 13.5, 18)"
+ print(0.9 * Vector3i(10, 15, 20)) # Prints (9.0, 13.5, 18.0)
[/codeblock]
@@ -131,7 +131,7 @@
Multiplies each component of the [Vector4i] by the given [float]. Returns a [Vector4].
[codeblock]
- print(0.9 * Vector4i(10, 15, 20, -10)) # Prints "(9, 13.5, 18, -9)"
+ print(0.9 * Vector4i(10, 15, 20, -10)) # Prints (9.0, 13.5, 18.0, -9.0)
[/codeblock]
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 14bbe635a4f0..bdcd9fe4849f 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1099,7 +1099,11 @@ Ref TextureStorage::texture_2d_get(RID p_texture) const {
ERR_FAIL_COND_V(data.is_empty(), Ref());
image = Image::create_from_data(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, texture->real_format, data);
- ERR_FAIL_COND_V(image->is_empty(), Ref());
+ if (image->is_empty()) {
+ const String &path_str = texture->path.is_empty() ? "with no path" : vformat("with path '%s'", texture->path);
+ ERR_FAIL_V_MSG(Ref(), vformat("Texture %s has no data.", path_str));
+ }
+
if (texture->format != texture->real_format) {
image->convert(texture->format);
}
@@ -1155,7 +1159,10 @@ Ref TextureStorage::texture_2d_get(RID p_texture) const {
ERR_FAIL_COND_V(data.is_empty(), Ref());
image = Image::create_from_data(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data);
- ERR_FAIL_COND_V(image->is_empty(), Ref());
+ if (image->is_empty()) {
+ const String &path_str = texture->path.is_empty() ? "with no path" : vformat("with path '%s'", texture->path);
+ ERR_FAIL_V_MSG(Ref(), vformat("Texture %s has no data.", path_str));
+ }
if (texture->format != Image::FORMAT_RGBA8) {
image->convert(texture->format);
@@ -1227,7 +1234,10 @@ Ref TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) cons
ERR_FAIL_COND_V(data.is_empty(), Ref());
Ref image = Image::create_from_data(texture->width, texture->height, false, Image::FORMAT_RGBA8, data);
- ERR_FAIL_COND_V(image->is_empty(), Ref());
+ if (image->is_empty()) {
+ const String &path_str = texture->path.is_empty() ? "with no path" : vformat("with path '%s'", texture->path);
+ ERR_FAIL_V_MSG(Ref(), vformat("Texture %s has no data.", path_str));
+ }
if (texture->format != Image::FORMAT_RGBA8) {
image->convert(texture->format);
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 76a1c9b04d3f..95eb3702aed7 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -358,14 +358,18 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
log->push_color(theme_cache.error_color);
Ref icon = theme_cache.error_icon;
log->add_image(icon);
- log->add_text(" ");
+ log->push_bold();
+ log->add_text(" ERROR: ");
+ log->pop(); // bold
tool_button->set_button_icon(icon);
} break;
case MSG_TYPE_WARNING: {
log->push_color(theme_cache.warning_color);
Ref icon = theme_cache.warning_icon;
log->add_image(icon);
- log->add_text(" ");
+ log->push_bold();
+ log->add_text(" WARNING: ");
+ log->pop(); // bold
tool_button->set_button_icon(icon);
} break;
case MSG_TYPE_EDITOR: {
diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp
index 7ef982353713..21967f3e0880 100644
--- a/editor/gui/editor_file_dialog.cpp
+++ b/editor/gui/editor_file_dialog.cpp
@@ -42,6 +42,7 @@
#include "editor/themes/editor_scale.h"
#include "scene/gui/center_container.h"
#include "scene/gui/check_box.h"
+#include "scene/gui/flow_container.h"
#include "scene/gui/grid_container.h"
#include "scene/gui/label.h"
#include "scene/gui/option_button.h"
@@ -1951,30 +1952,38 @@ void EditorFileDialog::_update_option_controls() {
}
options_dirty = false;
- while (grid_options->get_child_count() > 0) {
- Node *child = grid_options->get_child(0);
- grid_options->remove_child(child);
+ while (flow_checkbox_options->get_child_count() > 0) {
+ Node *child = flow_checkbox_options->get_child(0);
+ flow_checkbox_options->remove_child(child);
child->queue_free();
}
+ while (grid_select_options->get_child_count() > 0) {
+ Node *child = grid_select_options->get_child(0);
+ grid_select_options->remove_child(child);
+ child->queue_free();
+ }
+
selected_options.clear();
for (const EditorFileDialog::Option &opt : options) {
- Label *lbl = memnew(Label);
- lbl->set_text(opt.name);
- grid_options->add_child(lbl);
if (opt.values.is_empty()) {
CheckBox *cb = memnew(CheckBox);
cb->set_pressed(opt.default_idx);
- grid_options->add_child(cb);
+ cb->set_text(opt.name);
+ flow_checkbox_options->add_child(cb);
cb->connect(SceneStringName(toggled), callable_mp(this, &EditorFileDialog::_option_changed_checkbox_toggled).bind(opt.name));
selected_options[opt.name] = (bool)opt.default_idx;
} else {
+ Label *lbl = memnew(Label);
+ lbl->set_text(opt.name);
+ grid_select_options->add_child(lbl);
+
OptionButton *ob = memnew(OptionButton);
for (const String &val : opt.values) {
ob->add_item(val);
}
ob->select(opt.default_idx);
- grid_options->add_child(ob);
+ grid_select_options->add_child(ob);
ob->connect(SceneStringName(item_selected), callable_mp(this, &EditorFileDialog::_option_changed_item_selected).bind(opt.name));
selected_options[opt.name] = opt.default_idx;
}
@@ -2266,11 +2275,13 @@ void EditorFileDialog::add_side_menu(Control *p_menu, const String &p_title) {
void EditorFileDialog::_update_side_menu_visibility(bool p_native_dlg) {
if (p_native_dlg) {
pathhb->set_visible(false);
- grid_options->set_visible(false);
+ flow_checkbox_options->set_visible(false);
+ grid_select_options->set_visible(false);
list_hb->set_visible(false);
} else {
pathhb->set_visible(true);
- grid_options->set_visible(true);
+ flow_checkbox_options->set_visible(true);
+ grid_select_options->set_visible(true);
list_hb->set_visible(true);
}
}
@@ -2372,10 +2383,15 @@ EditorFileDialog::EditorFileDialog() {
body_hsplit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vbc->add_child(body_hsplit);
- grid_options = memnew(GridContainer);
- grid_options->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
- grid_options->set_columns(2);
- vbc->add_child(grid_options);
+ flow_checkbox_options = memnew(HFlowContainer);
+ flow_checkbox_options->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ flow_checkbox_options->set_alignment(FlowContainer::ALIGNMENT_CENTER);
+ vbc->add_child(flow_checkbox_options);
+
+ grid_select_options = memnew(GridContainer);
+ grid_select_options->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
+ grid_select_options->set_columns(2);
+ vbc->add_child(grid_select_options);
list_hb = memnew(HSplitContainer);
list_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/editor/gui/editor_file_dialog.h b/editor/gui/editor_file_dialog.h
index 8a07a2094372..d1b37687df85 100644
--- a/editor/gui/editor_file_dialog.h
+++ b/editor/gui/editor_file_dialog.h
@@ -39,6 +39,7 @@
class DependencyRemoveDialog;
class GridContainer;
class HSplitContainer;
+class HFlowContainer;
class ItemList;
class MenuButton;
class OptionButton;
@@ -94,7 +95,8 @@ class EditorFileDialog : public ConfirmationDialog {
Button *makedir = nullptr;
Access access = ACCESS_RESOURCES;
- GridContainer *grid_options = nullptr;
+ HFlowContainer *flow_checkbox_options = nullptr;
+ GridContainer *grid_select_options = nullptr;
VBoxContainer *vbox = nullptr;
FileMode mode = FILE_MODE_SAVE_FILE;
bool can_create_dir = false;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 094b14722e39..82c2e3e4bd6c 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4074,6 +4074,7 @@ void CanvasItemEditor::_notification(int p_what) {
case NOTIFICATION_READY: {
_update_lock_and_group_button();
+ SceneTreeDock::get_singleton()->get_tree_editor()->connect("node_changed", callable_mp(this, &CanvasItemEditor::_update_lock_and_group_button));
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &CanvasItemEditor::_project_settings_changed));
} break;
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 40c13ea3c4e1..7c4c3e25d2be 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -73,9 +73,17 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const {
} break;
case CONCAVE_POLYGON_SHAPE: {
+ Ref shape = node->get_shape();
+ const Vector &segments = shape->get_segments();
+ return segments[idx];
+
} break;
case CONVEX_POLYGON_SHAPE: {
+ Ref shape = node->get_shape();
+ const Vector &points = shape->get_points();
+ return points[idx];
+
} break;
case WORLD_BOUNDARY_SHAPE: {
@@ -145,9 +153,27 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
} break;
case CONCAVE_POLYGON_SHAPE: {
+ Ref concave_shape = node->get_shape();
+
+ Vector segments = concave_shape->get_segments();
+
+ ERR_FAIL_INDEX(idx, segments.size());
+ segments.write[idx] = p_point;
+
+ concave_shape->set_segments(segments);
+
} break;
case CONVEX_POLYGON_SHAPE: {
+ Ref convex_shape = node->get_shape();
+
+ Vector points = convex_shape->get_points();
+
+ ERR_FAIL_INDEX(idx, points.size());
+ points.write[idx] = p_point;
+
+ convex_shape->set_points(points);
+
} break;
case WORLD_BOUNDARY_SHAPE: {
@@ -237,11 +263,33 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
} break;
case CONCAVE_POLYGON_SHAPE: {
- // Cannot be edited directly, use CollisionPolygon2D instead.
+ Ref concave_shape = node->get_shape();
+
+ Vector2 values = p_org;
+
+ Vector undo_segments = concave_shape->get_segments();
+
+ ERR_FAIL_INDEX(idx, undo_segments.size());
+ undo_segments.write[idx] = values;
+
+ undo_redo->add_do_method(concave_shape.ptr(), "set_segments", concave_shape->get_segments());
+ undo_redo->add_undo_method(concave_shape.ptr(), "set_segments", undo_segments);
+
} break;
case CONVEX_POLYGON_SHAPE: {
- // Cannot be edited directly, use CollisionPolygon2D instead.
+ Ref convex_shape = node->get_shape();
+
+ Vector2 values = p_org;
+
+ Vector undo_points = convex_shape->get_points();
+
+ ERR_FAIL_INDEX(idx, undo_points.size());
+ undo_points.write[idx] = values;
+
+ undo_redo->add_do_method(convex_shape.ptr(), "set_points", convex_shape->get_points());
+ undo_redo->add_undo_method(convex_shape.ptr(), "set_points", undo_points);
+
} break;
case WORLD_BOUNDARY_SHAPE: {
@@ -471,9 +519,29 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla
} break;
case CONCAVE_POLYGON_SHAPE: {
+ Ref shape = current_shape;
+
+ const Vector &segments = shape->get_segments();
+
+ handles.resize(segments.size());
+ for (int i = 0; i < handles.size(); i++) {
+ handles.write[i] = segments[i];
+ p_overlay->draw_texture(h, gt.xform(handles[i]) - size);
+ }
+
} break;
case CONVEX_POLYGON_SHAPE: {
+ Ref shape = current_shape;
+
+ const Vector &points = shape->get_points();
+
+ handles.resize(points.size());
+ for (int i = 0; i < handles.size(); i++) {
+ handles.write[i] = points[i];
+ p_overlay->draw_texture(h, gt.xform(handles[i]) - size);
+ }
+
} break;
case WORLD_BOUNDARY_SHAPE: {
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 470e44d8eb13..f0008406958e 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -1817,6 +1817,12 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) {
break;
}
+ if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_RULER) {
+ EditorNode::get_singleton()->get_scene_root()->add_child(ruler);
+ collision_reposition = true;
+ break;
+ }
+
if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_LIST_SELECT) {
_list_select(b);
break;
@@ -1953,6 +1959,15 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) {
surface->queue_redraw();
} else {
+ if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_RULER) {
+ EditorNode::get_singleton()->get_scene_root()->remove_child(ruler);
+ ruler_start_point->set_visible(false);
+ ruler_end_point->set_visible(false);
+ ruler_label->set_visible(false);
+ collision_reposition = false;
+ break;
+ }
+
if (_edit.gizmo.is_valid()) {
_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, false);
spatial_editor->get_single_selected_node()->update_gizmos();
@@ -2882,6 +2897,24 @@ void Node3DEditorViewport::_notification(int p_what) {
} break;
case NOTIFICATION_PROCESS: {
+ if (ruler->is_inside_tree()) {
+ Vector3 start_pos = ruler_start_point->get_global_position();
+ Vector3 end_pos = ruler_end_point->get_global_position();
+
+ geometry->clear_surfaces();
+ geometry->surface_begin(Mesh::PRIMITIVE_LINES);
+ geometry->surface_add_vertex(start_pos);
+ geometry->surface_add_vertex(end_pos);
+ geometry->surface_end();
+
+ float distance = start_pos.distance_to(end_pos);
+ ruler_label->set_text(TS->format_number(vformat("%.3f m", distance)));
+
+ Vector3 center = (start_pos + end_pos) / 2;
+ Vector2 screen_position = camera->unproject_position(center) - (ruler_label->get_custom_minimum_size() / 2);
+ ruler_label->set_position(screen_position);
+ }
+
real_t delta = get_process_delta_time();
if (zoom_indicator_delay > 0) {
@@ -3094,15 +3127,37 @@ void Node3DEditorViewport::_notification(int p_what) {
case NOTIFICATION_PHYSICS_PROCESS: {
if (collision_reposition) {
- List &selection = editor_selection->get_selected_node_list();
-
- if (selection.size() == 1) {
- Node3D *first_selected_node = Object::cast_to(selection.front()->get());
- double snap = EDITOR_GET("interface/inspector/default_float_step");
- int snap_step_decimals = Math::range_step_decimals(snap);
- set_message(TTR("Translating:") + " (" + String::num(first_selected_node->get_global_position().x, snap_step_decimals) + ", " +
- String::num(first_selected_node->get_global_position().y, snap_step_decimals) + ", " + String::num(first_selected_node->get_global_position().z, snap_step_decimals) + ")");
- first_selected_node->set_global_position(spatial_editor->snap_point(_get_instance_position(_edit.mouse_pos, first_selected_node)));
+ Node3D *selected_node = nullptr;
+
+ if (ruler->is_inside_tree()) {
+ if (ruler_start_point->is_visible()) {
+ selected_node = ruler_end_point;
+ } else {
+ selected_node = ruler_start_point;
+ }
+ } else {
+ List &selection = editor_selection->get_selected_node_list();
+ if (selection.size() == 1) {
+ selected_node = Object::cast_to(selection.front()->get());
+ }
+ }
+
+ if (selected_node) {
+ if (!ruler->is_inside_tree()) {
+ double snap = EDITOR_GET("interface/inspector/default_float_step");
+ int snap_step_decimals = Math::range_step_decimals(snap);
+ set_message(TTR("Translating:") + " (" + String::num(selected_node->get_global_position().x, snap_step_decimals) + ", " +
+ String::num(selected_node->get_global_position().y, snap_step_decimals) + ", " + String::num(selected_node->get_global_position().z, snap_step_decimals) + ")");
+ }
+
+ selected_node->set_global_position(spatial_editor->snap_point(_get_instance_position(_edit.mouse_pos, selected_node)));
+
+ if (ruler->is_inside_tree() && !ruler_start_point->is_visible()) {
+ ruler_end_point->set_global_position(ruler_start_point->get_global_position());
+ ruler_start_point->set_visible(true);
+ ruler_end_point->set_visible(true);
+ ruler_label->set_visible(true);
+ }
}
}
@@ -4311,7 +4366,7 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos, Node3D
HashSet rids;
- if (!preview_node->is_inside_tree()) {
+ if (!preview_node->is_inside_tree() && !ruler->is_inside_tree()) {
List &selection = editor_selection->get_selected_node_list();
Node3D *first_selected_node = Object::cast_to(selection.front()->get());
@@ -5739,6 +5794,53 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
viewport->set_as_audio_listener_3d(true);
}
+ ruler = memnew(Node);
+
+ ruler_start_point = memnew(Node3D);
+ ruler_start_point->set_visible(false);
+
+ ruler_end_point = memnew(Node3D);
+ ruler_end_point->set_visible(false);
+
+ ruler_material.instantiate();
+ ruler_material->set_albedo(Color(1.0, 0.9, 0.0, 1.0));
+ ruler_material->set_flag(BaseMaterial3D::FLAG_DISABLE_FOG, true);
+ ruler_material->set_shading_mode(BaseMaterial3D::SHADING_MODE_UNSHADED);
+ ruler_material->set_depth_draw_mode(BaseMaterial3D::DEPTH_DRAW_DISABLED);
+
+ ruler_material_xray.instantiate();
+ ruler_material_xray->set_albedo(Color(1.0, 0.9, 0.0, 0.15));
+ ruler_material_xray->set_flag(BaseMaterial3D::FLAG_DISABLE_FOG, true);
+ ruler_material_xray->set_shading_mode(BaseMaterial3D::SHADING_MODE_UNSHADED);
+ ruler_material_xray->set_flag(BaseMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
+ ruler_material_xray->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA);
+ ruler_material_xray->set_render_priority(BaseMaterial3D::RENDER_PRIORITY_MAX);
+
+ geometry.instantiate();
+
+ ruler_line = memnew(MeshInstance3D);
+ ruler_line->set_mesh(geometry);
+ ruler_line->set_material_override(ruler_material);
+
+ ruler_line_xray = memnew(MeshInstance3D);
+ ruler_line_xray->set_mesh(geometry);
+ ruler_line_xray->set_material_override(ruler_material_xray);
+
+ ruler_label = memnew(Label);
+ ruler_label->add_theme_color_override(SceneStringName(font_color), Color(1.0, 0.9, 0.0, 1.0));
+ ruler_label->add_theme_color_override("font_outline_color", Color(0.0, 0.0, 0.0, 1.0));
+ ruler_label->add_theme_constant_override("outline_size", 4 * EDSCALE);
+ ruler_label->add_theme_font_size_override(SceneStringName(font_size), 15 * EDSCALE);
+ ruler_label->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("bold"), EditorStringName(EditorFonts)));
+ ruler_label->set_visible(false);
+
+ ruler->add_child(ruler_start_point);
+ ruler->add_child(ruler_end_point);
+ ruler->add_child(ruler_line);
+ ruler->add_child(ruler_line_xray);
+
+ viewport->add_child(ruler_label);
+
view_type = VIEW_TYPE_USER;
_update_name();
@@ -5746,6 +5848,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
}
Node3DEditorViewport::~Node3DEditorViewport() {
+ memdelete(ruler);
memdelete(frame_time_gradient);
}
@@ -6860,6 +6963,14 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
undo_redo->add_undo_method(this, "_refresh_menu_icons");
undo_redo->commit_action();
} break;
+ case MENU_RULER: {
+ for (int i = 0; i < TOOL_MAX; i++) {
+ tool_button[i]->set_pressed(i == p_option);
+ }
+ tool_button[TOOL_RULER]->set_pressed(true);
+ tool_mode = ToolMode::TOOL_RULER;
+ update_transform_gizmo();
+ } break;
}
}
@@ -8024,6 +8135,7 @@ void Node3DEditor::_update_theme() {
tool_button[TOOL_UNLOCK_SELECTED]->set_button_icon(get_editor_theme_icon(SNAME("Unlock")));
tool_button[TOOL_GROUP_SELECTED]->set_button_icon(get_editor_theme_icon(SNAME("Group")));
tool_button[TOOL_UNGROUP_SELECTED]->set_button_icon(get_editor_theme_icon(SNAME("Ungroup")));
+ tool_button[TOOL_RULER]->set_button_icon(get_editor_theme_icon(SNAME("Ruler")));
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_button_icon(get_editor_theme_icon(SNAME("Object")));
tool_option_button[TOOL_OPT_USE_SNAP]->set_button_icon(get_editor_theme_icon(SNAME("Snap")));
@@ -8773,6 +8885,15 @@ Node3DEditor::Node3DEditor() {
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/ungroup_selected_nodes"));
+ tool_button[TOOL_RULER] = memnew(Button);
+ main_menu_hbox->add_child(tool_button[TOOL_RULER]);
+ tool_button[TOOL_RULER]->set_toggle_mode(true);
+ tool_button[TOOL_RULER]->set_theme_type_variation("FlatButton");
+ tool_button[TOOL_RULER]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_RULER));
+ tool_button[TOOL_RULER]->set_tooltip_text(TTR("LMB+Drag: Measure the distance between two points in 3D space."));
+ // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
+ tool_button[TOOL_RULER]->set_shortcut(ED_SHORTCUT("spatial_editor/measure", TTR("Ruler Mode"), Key::M));
+
main_menu_hbox->add_child(memnew(VSeparator));
tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(Button);
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 243a712c3adf..54620562f97f 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -38,6 +38,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/spin_box.h"
+#include "scene/resources/immediate_mesh.h"
class AcceptDialog;
class CheckBox;
@@ -61,6 +62,7 @@ class VSeparator;
class VSplitContainer;
class ViewportNavigationControl;
class WorldEnvironment;
+class MeshInstance3D;
class ViewportRotationControl : public Control {
GDCLASS(ViewportRotationControl, Control);
@@ -214,6 +216,16 @@ class Node3DEditorViewport : public Control {
double gpu_time_history[FRAME_TIME_HISTORY];
int gpu_time_history_index;
+ Node *ruler = nullptr;
+ Node3D *ruler_start_point = nullptr;
+ Node3D *ruler_end_point = nullptr;
+ Ref geometry;
+ MeshInstance3D *ruler_line = nullptr;
+ MeshInstance3D *ruler_line_xray = nullptr;
+ Label *ruler_label = nullptr;
+ Ref ruler_material;
+ Ref ruler_material_xray;
+
int index;
ViewType view_type;
void _menu_option(int p_option);
@@ -621,6 +633,7 @@ class Node3DEditor : public VBoxContainer {
TOOL_UNLOCK_SELECTED,
TOOL_GROUP_SELECTED,
TOOL_UNGROUP_SELECTED,
+ TOOL_RULER,
TOOL_MAX
};
@@ -726,7 +739,8 @@ class Node3DEditor : public VBoxContainer {
MENU_UNLOCK_SELECTED,
MENU_GROUP_SELECTED,
MENU_UNGROUP_SELECTED,
- MENU_SNAP_TO_FLOOR
+ MENU_SNAP_TO_FLOOR,
+ MENU_RULER,
};
Button *tool_button[TOOL_MAX];
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index d44a3e24cd57..6c6754d5db59 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -65,6 +65,7 @@ static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = {
"sampler2DArray",
"sampler3D",
"samplerCube",
+ "samplerExternalOES",
};
class ShaderGlobalsEditorInterface : public Object {
@@ -232,6 +233,11 @@ class ShaderGlobalsEditorInterface : public Object {
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
pinfo.hint_string = "Cubemap,CompressedCubemap";
} break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLEREXT: {
+ pinfo.type = Variant::OBJECT;
+ pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pinfo.hint_string = "ExternalTexture";
+ } break;
default: {
} break;
}
@@ -339,6 +345,9 @@ static Variant create_var(RS::GlobalShaderParameterType p_type) {
case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {
return "";
}
+ case RS::GLOBAL_VAR_TYPE_SAMPLEREXT: {
+ return "";
+ }
default: {
return Variant();
}
diff --git a/main/main.cpp b/main/main.cpp
index 0b3dcc3f5bd2..93551555e654 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -4441,15 +4441,20 @@ bool Main::iteration() {
RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames.
- if ((DisplayServer::get_singleton()->can_any_window_draw() || DisplayServer::get_singleton()->has_additional_outputs()) &&
- RenderingServer::get_singleton()->is_render_loop_enabled()) {
+ const bool has_pending_resources_for_processing = RD::get_singleton() && RD::get_singleton()->has_pending_resources_for_processing();
+ bool wants_present = (DisplayServer::get_singleton()->can_any_window_draw() ||
+ DisplayServer::get_singleton()->has_additional_outputs()) &&
+ RenderingServer::get_singleton()->is_render_loop_enabled();
+
+ if (wants_present || has_pending_resources_for_processing) {
+ wants_present |= force_redraw_requested;
if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) {
if (RenderingServer::get_singleton()->has_changed()) {
- RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands
+ RenderingServer::get_singleton()->draw(wants_present, scaled_step); // flush visual commands
Engine::get_singleton()->increment_frames_drawn();
}
} else {
- RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands
+ RenderingServer::get_singleton()->draw(wants_present, scaled_step); // flush visual commands
Engine::get_singleton()->increment_frames_drawn();
force_redraw_requested = false;
}
diff --git a/misc/extension_api_validation/4.3-stable.expected b/misc/extension_api_validation/4.3-stable.expected
index 1bbe720eb944..8cade432e64d 100644
--- a/misc/extension_api_validation/4.3-stable.expected
+++ b/misc/extension_api_validation/4.3-stable.expected
@@ -215,3 +215,16 @@ Validate extension JSON: Error: Field 'classes/Control/properties/offset_right':
Validate extension JSON: Error: Field 'classes/Control/properties/offset_top': type changed value in new API, from "int" to "float".
Property type changed to float to match the actual internal API and documentation.
+
+
+GH-100129
+---------
+Validate extension JSON: Error: Field 'classes/NavigationServer2D/methods/query_path': is_const changed value in new API, from true to false.
+Validate extension JSON: Error: Field 'classes/NavigationServer3D/methods/query_path': is_const changed value in new API, from true to false.
+Validate extension JSON: Error: Field 'classes/NavigationServer2D/methods/query_path/arguments': size changed value in new API, from 2 to 3.
+Validate extension JSON: Error: Field 'classes/NavigationServer3D/methods/query_path/arguments': size changed value in new API, from 2 to 3.
+Validate extension JSON: Error: Field 'classes/NavigationServer2D/methods/map_get_path': is_const changed value in new API, from true to false.
+Validate extension JSON: Error: Field 'classes/NavigationServer3D/methods/map_get_path': is_const changed value in new API, from true to false.
+
+`query_path` and `map_get_path` methods changed to be non const due to internal compatibility and server changes.
+Added optional callback parameters to `query_path` functions. Compatibility methods registered.
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index faf6ffb6ac1b..0c56cb2654f3 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -1637,7 +1637,15 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali
bool valid = true;
if (!valid_annotations.has(annotation->name)) {
- push_error(vformat(R"(Unrecognized annotation: "%s".)", annotation->name));
+ if (annotation->name == "@deprecated") {
+ push_error(R"("@deprecated" annotation does not exist. Use "## @deprecated: Reason here." instead.)");
+ } else if (annotation->name == "@experimental") {
+ push_error(R"("@experimental" annotation does not exist. Use "## @experimental: Reason here." instead.)");
+ } else if (annotation->name == "@tutorial") {
+ push_error(R"("@tutorial" annotation does not exist. Use "## @tutorial(Title): https://example.com" instead.)");
+ } else {
+ push_error(vformat(R"(Unrecognized annotation: "%s".)", annotation->name));
+ }
valid = false;
}
diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_deprecated.gd b/modules/gdscript/tests/scripts/parser/errors/annotation_deprecated.gd
new file mode 100644
index 000000000000..95569c48de70
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/annotation_deprecated.gd
@@ -0,0 +1,5 @@
+# This annotation should be used within a documentation comment instead:
+# ## @deprecated: Reason here.
+
+@deprecated
+var some_variable = "value"
diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_deprecated.out b/modules/gdscript/tests/scripts/parser/errors/annotation_deprecated.out
new file mode 100644
index 000000000000..a99608890203
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/annotation_deprecated.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+"@deprecated" annotation does not exist. Use "## @deprecated: Reason here." instead.
diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_experimental.gd b/modules/gdscript/tests/scripts/parser/errors/annotation_experimental.gd
new file mode 100644
index 000000000000..ce00639de6d4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/annotation_experimental.gd
@@ -0,0 +1,6 @@
+# This annotation should be used within a documentation comment instead:
+# ## @experimental: Reason here.
+
+@experimental("This function isn't implemented yet.")
+func say_hello():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_experimental.out b/modules/gdscript/tests/scripts/parser/errors/annotation_experimental.out
new file mode 100644
index 000000000000..d7e1c2eb2f2f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/annotation_experimental.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+"@experimental" annotation does not exist. Use "## @experimental: Reason here." instead.
diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_tutorial.gd b/modules/gdscript/tests/scripts/parser/errors/annotation_tutorial.gd
new file mode 100644
index 000000000000..ccd995bb5018
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/annotation_tutorial.gd
@@ -0,0 +1,5 @@
+# This annotation should be used within a documentation comment instead:
+# ## @tutorial(Title): https://example.com
+
+@tutorial("https://example.com")
+const SOME_CONSTANT = "value"
diff --git a/modules/gdscript/tests/scripts/parser/errors/annotation_tutorial.out b/modules/gdscript/tests/scripts/parser/errors/annotation_tutorial.out
new file mode 100644
index 000000000000..7d8be3567bf0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/annotation_tutorial.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+"@tutorial" annotation does not exist. Use "## @tutorial(Title): https://example.com" instead.
diff --git a/modules/navigation/2d/godot_navigation_server_2d.cpp b/modules/navigation/2d/godot_navigation_server_2d.cpp
index 2af125d43481..de78ea5826a8 100644
--- a/modules/navigation/2d/godot_navigation_server_2d.cpp
+++ b/modules/navigation/2d/godot_navigation_server_2d.cpp
@@ -81,12 +81,6 @@
return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1))); \
}
-#define FORWARD_5_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, T_4, D_4, CONV_0, CONV_1, CONV_2, CONV_3, CONV_4) \
- GodotNavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3, T_4 D_4) \
- const { \
- return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3), CONV_4(D_4))); \
- }
-
static RID rid_to_rid(const RID d) {
return d;
}
@@ -277,7 +271,9 @@ real_t FORWARD_1_C(map_get_edge_connection_margin, RID, p_map, rid_to_rid);
void FORWARD_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius, rid_to_rid, real_to_real);
real_t FORWARD_1_C(map_get_link_connection_radius, RID, p_map, rid_to_rid);
-Vector FORWARD_5_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2, p_origin, Vector2, p_destination, bool, p_optimize, uint32_t, p_layers, rid_to_rid, v2_to_v3, v2_to_v3, bool_to_bool, uint32_to_uint32);
+Vector GodotNavigationServer2D::map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers) {
+ return vector_v3_to_v2(NavigationServer3D::get_singleton()->map_get_path(p_map, v2_to_v3(p_origin), v2_to_v3(p_destination), p_optimize, p_navigation_layers));
+}
Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
RID FORWARD_2_C(map_get_closest_point_owner, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
@@ -456,16 +452,48 @@ Vector GodotNavigationServer2D::obstacle_get_vertices(RID p_obstacle) c
return vector_v3_to_v2(NavigationServer3D::get_singleton()->obstacle_get_vertices(p_obstacle));
}
-void GodotNavigationServer2D::query_path(const Ref &p_query_parameters, Ref p_query_result) const {
+void GodotNavigationServer2D::query_path(const Ref &p_query_parameters, Ref p_query_result, const Callable &p_callback) {
ERR_FAIL_COND(!p_query_parameters.is_valid());
ERR_FAIL_COND(!p_query_result.is_valid());
- const NavigationUtilities::PathQueryResult _query_result = NavigationServer3D::get_singleton()->_query_path(p_query_parameters->get_parameters());
+ Ref query_parameters;
+ query_parameters.instantiate();
+
+ query_parameters->set_map(p_query_parameters->get_map());
+ query_parameters->set_start_position(v2_to_v3(p_query_parameters->get_start_position()));
+ query_parameters->set_target_position(v2_to_v3(p_query_parameters->get_target_position()));
+ query_parameters->set_navigation_layers(p_query_parameters->get_navigation_layers());
+ query_parameters->set_pathfinding_algorithm(NavigationPathQueryParameters3D::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR);
+
+ switch (p_query_parameters->get_path_postprocessing()) {
+ case NavigationPathQueryParameters2D::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL: {
+ query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL);
+ } break;
+ case NavigationPathQueryParameters2D::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED: {
+ query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED);
+ } break;
+ case NavigationPathQueryParameters2D::PathPostProcessing::PATH_POSTPROCESSING_NONE: {
+ query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_NONE);
+ } break;
+ default: {
+ WARN_PRINT("No match for used PathPostProcessing - fallback to default");
+ query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL);
+ } break;
+ }
+
+ query_parameters->set_metadata_flags((int64_t)p_query_parameters->get_metadata_flags());
+ query_parameters->set_simplify_path(p_query_parameters->get_simplify_path());
+ query_parameters->set_simplify_epsilon(p_query_parameters->get_simplify_epsilon());
+
+ Ref query_result;
+ query_result.instantiate();
+
+ NavigationServer3D::get_singleton()->query_path(query_parameters, query_result, p_callback);
- p_query_result->set_path(vector_v3_to_v2(_query_result.path));
- p_query_result->set_path_types(_query_result.path_types);
- p_query_result->set_path_rids(_query_result.path_rids);
- p_query_result->set_path_owner_ids(_query_result.path_owner_ids);
+ p_query_result->set_path(vector_v3_to_v2(query_result->get_path()));
+ p_query_result->set_path_types(query_result->get_path_types());
+ p_query_result->set_path_rids(query_result->get_path_rids());
+ p_query_result->set_path_owner_ids(query_result->get_path_owner_ids());
}
RID GodotNavigationServer2D::source_geometry_parser_create() {
diff --git a/modules/navigation/2d/godot_navigation_server_2d.h b/modules/navigation/2d/godot_navigation_server_2d.h
index 1579ca290741..80fdea5ba9db 100644
--- a/modules/navigation/2d/godot_navigation_server_2d.h
+++ b/modules/navigation/2d/godot_navigation_server_2d.h
@@ -68,7 +68,7 @@ class GodotNavigationServer2D : public NavigationServer2D {
virtual real_t map_get_edge_connection_margin(RID p_map) const override;
virtual void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) override;
virtual real_t map_get_link_connection_radius(RID p_map) const override;
- virtual Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const override;
+ virtual Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) override;
virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const override;
virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const override;
virtual TypedArray map_get_links(RID p_map) const override;
@@ -242,7 +242,7 @@ class GodotNavigationServer2D : public NavigationServer2D {
virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override;
virtual uint32_t obstacle_get_avoidance_layers(RID p_obstacle) const override;
- virtual void query_path(const Ref &p_query_parameters, Ref p_query_result) const override;
+ virtual void query_path(const Ref &p_query_parameters, Ref p_query_result, const Callable &p_callback) override;
virtual void init() override;
virtual void sync() override;
diff --git a/modules/navigation/3d/godot_navigation_server_3d.cpp b/modules/navigation/3d/godot_navigation_server_3d.cpp
index 5dfc39f6f5e0..80e87a4b2e8d 100644
--- a/modules/navigation/3d/godot_navigation_server_3d.cpp
+++ b/modules/navigation/3d/godot_navigation_server_3d.cpp
@@ -237,11 +237,29 @@ real_t GodotNavigationServer3D::map_get_link_connection_radius(RID p_map) const
return map->get_link_connection_radius();
}
-Vector GodotNavigationServer3D::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) const {
+Vector GodotNavigationServer3D::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) {
const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_NULL_V(map, Vector());
- return map->get_path(p_origin, p_destination, p_optimize, p_navigation_layers, nullptr, nullptr, nullptr);
+ Ref query_parameters;
+ query_parameters.instantiate();
+
+ query_parameters->set_map(p_map);
+ query_parameters->set_start_position(p_origin);
+ query_parameters->set_target_position(p_destination);
+ query_parameters->set_navigation_layers(p_navigation_layers);
+ query_parameters->set_pathfinding_algorithm(NavigationPathQueryParameters3D::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR);
+ query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL);
+ if (!p_optimize) {
+ query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PATH_POSTPROCESSING_EDGECENTERED);
+ }
+
+ Ref query_result;
+ query_result.instantiate();
+
+ query_path(query_parameters, query_result);
+
+ return query_result->get_path();
}
Vector3 GodotNavigationServer3D::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
@@ -1384,86 +1402,14 @@ void GodotNavigationServer3D::finish() {
#endif // _3D_DISABLED
}
-PathQueryResult GodotNavigationServer3D::_query_path(const PathQueryParameters &p_parameters) const {
- PathQueryResult r_query_result;
-
- const NavMap *map = map_owner.get_or_null(p_parameters.map);
- ERR_FAIL_NULL_V(map, r_query_result);
-
- // run the pathfinding
-
- if (p_parameters.pathfinding_algorithm == PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR) {
- // while postprocessing is still part of map.get_path() need to check and route it here for the correct "optimize" post-processing
- if (p_parameters.path_postprocessing == PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL) {
- r_query_result.path = map->get_path(
- p_parameters.start_position,
- p_parameters.target_position,
- true,
- p_parameters.navigation_layers,
- p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES) ? &r_query_result.path_types : nullptr,
- p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS) ? &r_query_result.path_rids : nullptr,
- p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS) ? &r_query_result.path_owner_ids : nullptr);
- } else if (p_parameters.path_postprocessing == PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED) {
- r_query_result.path = map->get_path(
- p_parameters.start_position,
- p_parameters.target_position,
- false,
- p_parameters.navigation_layers,
- p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES) ? &r_query_result.path_types : nullptr,
- p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS) ? &r_query_result.path_rids : nullptr,
- p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS) ? &r_query_result.path_owner_ids : nullptr);
- }
- } else {
- return r_query_result;
- }
-
- // add path postprocessing
-
- if (r_query_result.path.size() > 2 && p_parameters.simplify_path) {
- const LocalVector &simplified_path_indices = get_simplified_path_indices(r_query_result.path, p_parameters.simplify_epsilon);
-
- uint32_t indices_count = simplified_path_indices.size();
-
- {
- Vector3 *w = r_query_result.path.ptrw();
- const Vector3 *r = r_query_result.path.ptr();
- for (uint32_t i = 0; i < indices_count; i++) {
- w[i] = r[simplified_path_indices[i]];
- }
- r_query_result.path.resize(indices_count);
- }
-
- if (p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES)) {
- int32_t *w = r_query_result.path_types.ptrw();
- const int32_t *r = r_query_result.path_types.ptr();
- for (uint32_t i = 0; i < indices_count; i++) {
- w[i] = r[simplified_path_indices[i]];
- }
- r_query_result.path_types.resize(indices_count);
- }
-
- if (p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS)) {
- TypedArray simplified_path_rids;
- simplified_path_rids.resize(indices_count);
- for (uint32_t i = 0; i < indices_count; i++) {
- simplified_path_rids[i] = r_query_result.path_rids[i];
- }
- r_query_result.path_rids = simplified_path_rids;
- }
-
- if (p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS)) {
- int64_t *w = r_query_result.path_owner_ids.ptrw();
- const int64_t *r = r_query_result.path_owner_ids.ptr();
- for (uint32_t i = 0; i < indices_count; i++) {
- w[i] = r[simplified_path_indices[i]];
- }
- r_query_result.path_owner_ids.resize(indices_count);
- }
- }
+void GodotNavigationServer3D::query_path(const Ref &p_query_parameters, Ref p_query_result, const Callable &p_callback) {
+ ERR_FAIL_COND(p_query_parameters.is_null());
+ ERR_FAIL_COND(p_query_result.is_null());
- // add path stats
+ NavMap *map = map_owner.get_or_null(p_query_parameters->get_map());
+ ERR_FAIL_NULL(map);
- return r_query_result;
+ NavMeshQueries3D::map_query_path(map, p_query_parameters, p_query_result, p_callback);
}
RID GodotNavigationServer3D::source_geometry_parser_create() {
@@ -1490,84 +1436,30 @@ Vector GodotNavigationServer3D::simplify_path(const Vector &p_
p_epsilon = MAX(0.0, p_epsilon);
- LocalVector simplified_path_indices = get_simplified_path_indices(p_path, p_epsilon);
-
- uint32_t indices_count = simplified_path_indices.size();
-
- Vector simplified_path;
- simplified_path.resize(indices_count);
-
- Vector3 *w = simplified_path.ptrw();
- const Vector3 *r = p_path.ptr();
- for (uint32_t i = 0; i < indices_count; i++) {
- w[i] = r[simplified_path_indices[i]];
- }
-
- return simplified_path;
-}
-
-LocalVector GodotNavigationServer3D::get_simplified_path_indices(const Vector &p_path, real_t p_epsilon) {
- p_epsilon = MAX(0.0, p_epsilon);
- real_t squared_epsilon = p_epsilon * p_epsilon;
-
- LocalVector valid_points;
- valid_points.resize(p_path.size());
- for (uint32_t i = 0; i < valid_points.size(); i++) {
- valid_points[i] = false;
- }
-
- simplify_path_segment(0, p_path.size() - 1, p_path, squared_epsilon, valid_points);
-
- int valid_point_index = 0;
-
- for (bool valid : valid_points) {
- if (valid) {
- valid_point_index += 1;
- }
- }
-
- LocalVector simplified_path_indices;
- simplified_path_indices.resize(valid_point_index);
- valid_point_index = 0;
-
- for (uint32_t i = 0; i < valid_points.size(); i++) {
- if (valid_points[i]) {
- simplified_path_indices[valid_point_index] = i;
- valid_point_index += 1;
+ LocalVector source_path;
+ {
+ source_path.resize(p_path.size());
+ const Vector3 *r = p_path.ptr();
+ for (uint32_t i = 0; i < p_path.size(); i++) {
+ source_path[i] = r[i];
}
}
- return simplified_path_indices;
-}
-
-void GodotNavigationServer3D::simplify_path_segment(int p_start_inx, int p_end_inx, const Vector &p_points, real_t p_epsilon, LocalVector &r_valid_points) {
- r_valid_points[p_start_inx] = true;
- r_valid_points[p_end_inx] = true;
-
- const Vector3 &start_point = p_points[p_start_inx];
- const Vector3 &end_point = p_points[p_end_inx];
+ LocalVector simplified_path_indices = NavMeshQueries3D::get_simplified_path_indices(source_path, p_epsilon);
- Vector3 path_segment[2] = { start_point, end_point };
+ uint32_t index_count = simplified_path_indices.size();
- real_t point_max_distance = 0.0;
- int point_max_index = 0;
-
- for (int i = p_start_inx; i < p_end_inx; i++) {
- const Vector3 &checked_point = p_points[i];
-
- const Vector3 closest_point = Geometry3D::get_closest_point_to_segment(checked_point, path_segment);
- real_t distance_squared = closest_point.distance_squared_to(checked_point);
-
- if (distance_squared > point_max_distance) {
- point_max_index = i;
- point_max_distance = distance_squared;
+ Vector simplified_path;
+ {
+ simplified_path.resize(index_count);
+ Vector3 *w = simplified_path.ptrw();
+ const Vector3 *r = source_path.ptr();
+ for (uint32_t i = 0; i < index_count; i++) {
+ w[i] = r[simplified_path_indices[i]];
}
}
- if (point_max_distance > p_epsilon) {
- simplify_path_segment(p_start_inx, point_max_index, p_points, p_epsilon, r_valid_points);
- simplify_path_segment(point_max_index, p_end_inx, p_points, p_epsilon, r_valid_points);
- }
+ return simplified_path;
}
int GodotNavigationServer3D::get_process_info(ProcessInfo p_info) const {
diff --git a/modules/navigation/3d/godot_navigation_server_3d.h b/modules/navigation/3d/godot_navigation_server_3d.h
index eae6ea28608a..ce8d333535f2 100644
--- a/modules/navigation/3d/godot_navigation_server_3d.h
+++ b/modules/navigation/3d/godot_navigation_server_3d.h
@@ -40,6 +40,8 @@
#include "core/templates/local_vector.h"
#include "core/templates/rid.h"
#include "core/templates/rid_owner.h"
+#include "servers/navigation/navigation_path_query_parameters_3d.h"
+#include "servers/navigation/navigation_path_query_result_3d.h"
#include "servers/navigation_server_3d.h"
/// The commands are functions executed during the `sync` phase.
@@ -130,7 +132,7 @@ class GodotNavigationServer3D : public NavigationServer3D {
COMMAND_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius);
virtual real_t map_get_link_connection_radius(RID p_map) const override;
- virtual Vector map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const override;
+ virtual Vector map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) override;
virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const override;
virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const override;
@@ -273,10 +275,6 @@ class GodotNavigationServer3D : public NavigationServer3D {
virtual Vector simplify_path(const Vector &p_path, real_t p_epsilon) override;
-private:
- static void simplify_path_segment(int p_start_inx, int p_end_inx, const Vector &p_points, real_t p_epsilon, LocalVector &r_valid_points);
- static LocalVector get_simplified_path_indices(const Vector &p_path, real_t p_epsilon);
-
public:
COMMAND_1(free, RID, p_object);
@@ -288,7 +286,7 @@ class GodotNavigationServer3D : public NavigationServer3D {
virtual void sync() override;
virtual void finish() override;
- virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const override;
+ virtual void query_path(const Ref &p_query_parameters, Ref p_query_result, const Callable &p_callback = Callable()) override;
int get_process_info(ProcessInfo p_info) const override;
diff --git a/modules/navigation/3d/nav_mesh_queries_3d.cpp b/modules/navigation/3d/nav_mesh_queries_3d.cpp
index fa7ccbeb701a..b60d8d073dca 100644
--- a/modules/navigation/3d/nav_mesh_queries_3d.cpp
+++ b/modules/navigation/3d/nav_mesh_queries_3d.cpp
@@ -33,21 +33,22 @@
#include "nav_mesh_queries_3d.h"
#include "../nav_base.h"
+#include "../nav_map.h"
#include "core/math/geometry_3d.h"
+#include "servers/navigation/navigation_utilities.h"
#define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a)))
-#define APPEND_METADATA(poly) \
- if (r_path_types) { \
- r_path_types->push_back(poly->owner->get_type()); \
- } \
- if (r_path_rids) { \
- r_path_rids->push_back(poly->owner->get_self()); \
- } \
- if (r_path_owners) { \
- r_path_owners->push_back(poly->owner->get_owner_id()); \
- }
+bool NavMeshQueries3D::emit_callback(const Callable &p_callback) {
+ ERR_FAIL_COND_V(!p_callback.is_valid(), false);
+
+ Callable::CallError ce;
+ Variant result;
+ p_callback.callp(nullptr, 0, result, ce);
+
+ return ce.error == Callable::CallError::CALL_OK;
+}
Vector3 NavMeshQueries3D::polygons_get_random_point(const LocalVector &p_polygons, uint32_t p_navigation_layers, bool p_uniformly) {
const LocalVector ®ion_polygons = p_polygons;
@@ -127,87 +128,225 @@ Vector3 NavMeshQueries3D::polygons_get_random_point(const LocalVector NavMeshQueries3D::polygons_get_path(const LocalVector &p_polygons, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector *r_path_types, TypedArray *r_path_rids, Vector *r_path_owners, const Vector3 &p_map_up, uint32_t p_link_polygons_size) {
- // Clear metadata outputs.
- if (r_path_types) {
- r_path_types->clear();
+void NavMeshQueries3D::_query_task_create_same_polygon_two_point_path(NavMeshPathQueryTask3D &p_query_task, const gd::Polygon *begin_poly, Vector3 begin_point, const gd::Polygon *end_poly, Vector3 end_point) {
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES)) {
+ p_query_task.path_meta_point_types.resize(2);
+ p_query_task.path_meta_point_types[0] = begin_poly->owner->get_type();
+ p_query_task.path_meta_point_types[1] = end_poly->owner->get_type();
}
- if (r_path_rids) {
- r_path_rids->clear();
+
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS)) {
+ p_query_task.path_meta_point_rids.resize(2);
+ p_query_task.path_meta_point_rids[0] = begin_poly->owner->get_self();
+ p_query_task.path_meta_point_rids[1] = end_poly->owner->get_self();
}
- if (r_path_owners) {
- r_path_owners->clear();
+
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS)) {
+ p_query_task.path_meta_point_owners.resize(2);
+ p_query_task.path_meta_point_owners[0] = begin_poly->owner->get_owner_id();
+ p_query_task.path_meta_point_owners[1] = end_poly->owner->get_owner_id();
}
- // Find the start poly and the end poly on this map.
- const gd::Polygon *begin_poly = nullptr;
- const gd::Polygon *end_poly = nullptr;
- Vector3 begin_point;
- Vector3 end_point;
- real_t begin_d = FLT_MAX;
- real_t end_d = FLT_MAX;
- // Find the initial poly and the end poly on this map.
- for (const gd::Polygon &p : p_polygons) {
- // Only consider the polygon if it in a region with compatible layers.
- if ((p_navigation_layers & p.owner->get_navigation_layers()) == 0) {
- continue;
+ p_query_task.path_points.resize(2);
+ p_query_task.path_points[0] = begin_point;
+ p_query_task.path_points[1] = end_point;
+}
+
+void NavMeshQueries3D::_query_task_push_back_point_with_metadata(NavMeshPathQueryTask3D &p_query_task, Vector3 p_point, const gd::Polygon *p_point_polygon) {
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES)) {
+ p_query_task.path_meta_point_types.push_back(p_point_polygon->owner->get_type());
+ }
+
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS)) {
+ p_query_task.path_meta_point_rids.push_back(p_point_polygon->owner->get_self());
+ }
+
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS)) {
+ p_query_task.path_meta_point_owners.push_back(p_point_polygon->owner->get_owner_id());
+ }
+
+ p_query_task.path_points.push_back(p_point);
+}
+
+void NavMeshQueries3D::map_query_path(NavMap *map, const Ref &p_query_parameters, Ref p_query_result, const Callable &p_callback) {
+ ERR_FAIL_NULL(map);
+ ERR_FAIL_COND(p_query_parameters.is_null());
+ ERR_FAIL_COND(p_query_result.is_null());
+
+ using namespace NavigationUtilities;
+
+ NavMeshQueries3D::NavMeshPathQueryTask3D query_task;
+ query_task.start_position = p_query_parameters->get_start_position();
+ query_task.target_position = p_query_parameters->get_target_position();
+ query_task.navigation_layers = p_query_parameters->get_navigation_layers();
+ query_task.callback = p_callback;
+
+ switch (p_query_parameters->get_pathfinding_algorithm()) {
+ case NavigationPathQueryParameters3D::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR: {
+ query_task.pathfinding_algorithm = PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
+ } break;
+ default: {
+ WARN_PRINT("No match for used PathfindingAlgorithm - fallback to default");
+ query_task.pathfinding_algorithm = PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
+ } break;
+ }
+
+ switch (p_query_parameters->get_path_postprocessing()) {
+ case NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL: {
+ query_task.path_postprocessing = PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ } break;
+ case NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED: {
+ query_task.path_postprocessing = PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED;
+ } break;
+ case NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_NONE: {
+ query_task.path_postprocessing = PathPostProcessing::PATH_POSTPROCESSING_NONE;
+ } break;
+ default: {
+ WARN_PRINT("No match for used PathPostProcessing - fallback to default");
+ query_task.path_postprocessing = PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ } break;
+ }
+
+ query_task.metadata_flags = (int64_t)p_query_parameters->get_metadata_flags();
+ query_task.simplify_path = p_query_parameters->get_simplify_path();
+ query_task.simplify_epsilon = p_query_parameters->get_simplify_epsilon();
+ query_task.status = NavMeshPathQueryTask3D::TaskStatus::QUERY_STARTED;
+
+ map->query_path(query_task);
+
+ const uint32_t path_point_size = query_task.path_points.size();
+
+ Vector path_points;
+ Vector path_meta_point_types;
+ TypedArray path_meta_point_rids;
+ Vector path_meta_point_owners;
+
+ {
+ path_points.resize(path_point_size);
+ Vector3 *w = path_points.ptrw();
+ const Vector3 *r = query_task.path_points.ptr();
+ for (uint32_t i = 0; i < path_point_size; i++) {
+ w[i] = r[i];
}
+ }
- // For each face check the distance between the origin/destination
- for (size_t point_id = 2; point_id < p.points.size(); point_id++) {
- const Face3 face(p.points[0].pos, p.points[point_id - 1].pos, p.points[point_id].pos);
+ if (query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES)) {
+ path_meta_point_types.resize(path_point_size);
+ int32_t *w = path_meta_point_types.ptrw();
+ const int32_t *r = query_task.path_meta_point_types.ptr();
+ for (uint32_t i = 0; i < path_point_size; i++) {
+ w[i] = r[i];
+ }
+ }
+ if (query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS)) {
+ path_meta_point_rids.resize(path_point_size);
+ for (uint32_t i = 0; i < path_point_size; i++) {
+ path_meta_point_rids[i] = query_task.path_meta_point_rids[i];
+ }
+ }
+ if (query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS)) {
+ path_meta_point_owners.resize(path_point_size);
+ int64_t *w = path_meta_point_owners.ptrw();
+ const int64_t *r = query_task.path_meta_point_owners.ptr();
+ for (uint32_t i = 0; i < path_point_size; i++) {
+ w[i] = r[i];
+ }
+ }
- Vector3 point = face.get_closest_point_to(p_origin);
- real_t distance_to_point = point.distance_to(p_origin);
- if (distance_to_point < begin_d) {
- begin_d = distance_to_point;
- begin_poly = &p;
- begin_point = point;
- }
+ p_query_result->set_path(path_points);
+ p_query_result->set_path_types(path_meta_point_types);
+ p_query_result->set_path_rids(path_meta_point_rids);
+ p_query_result->set_path_owner_ids(path_meta_point_owners);
- point = face.get_closest_point_to(p_destination);
- distance_to_point = point.distance_to(p_destination);
- if (distance_to_point < end_d) {
- end_d = distance_to_point;
- end_poly = &p;
- end_point = point;
- }
+ if (query_task.callback.is_valid()) {
+ if (emit_callback(query_task.callback)) {
+ query_task.status = NavMeshPathQueryTask3D::TaskStatus::CALLBACK_DISPATCHED;
+ } else {
+ query_task.status = NavMeshPathQueryTask3D::TaskStatus::CALLBACK_FAILED;
}
}
+}
+
+void NavMeshQueries3D::query_task_polygons_get_path(NavMeshPathQueryTask3D &p_query_task, const LocalVector &p_polygons, const Vector3 &p_map_up, uint32_t p_link_polygons_size) {
+ p_query_task.path_points.clear();
+ p_query_task.path_meta_point_types.clear();
+ p_query_task.path_meta_point_rids.clear();
+ p_query_task.path_meta_point_owners.clear();
+
+ // Find begin polyon and begin position closest to start position and
+ // end polyon and end position closest to target position on the map.
+ const gd::Polygon *begin_poly = nullptr;
+ const gd::Polygon *end_poly = nullptr;
+ Vector3 begin_point;
+ Vector3 end_point;
+
+ _query_task_find_start_end_positions(p_query_task, p_polygons, &begin_poly, begin_point, &end_poly, end_point);
// Check for trivial cases
if (!begin_poly || !end_poly) {
- return Vector();
+ p_query_task.status = NavMeshPathQueryTask3D::TaskStatus::QUERY_FAILED;
+ return;
}
+
if (begin_poly == end_poly) {
- if (r_path_types) {
- r_path_types->resize(2);
- r_path_types->write[0] = begin_poly->owner->get_type();
- r_path_types->write[1] = end_poly->owner->get_type();
- }
+ _query_task_create_same_polygon_two_point_path(p_query_task, begin_poly, begin_point, end_poly, end_point);
+ return;
+ }
- if (r_path_rids) {
- r_path_rids->resize(2);
- (*r_path_rids)[0] = begin_poly->owner->get_self();
- (*r_path_rids)[1] = end_poly->owner->get_self();
- }
+ _query_task_build_path_corridor(p_query_task, p_polygons, p_map_up, p_link_polygons_size, begin_poly, begin_point, end_poly, end_point);
+
+ // Post-Process path.
+ switch (p_query_task.path_postprocessing) {
+ case PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL: {
+ _path_corridor_post_process_corridorfunnel(p_query_task, p_query_task.least_cost_id, begin_poly, begin_point, end_poly, end_point, p_map_up);
+ } break;
+ case PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED: {
+ _path_corridor_post_process_edgecentered(p_query_task, p_query_task.least_cost_id, begin_poly, begin_point, end_poly, end_point);
+ } break;
+ case PathPostProcessing::PATH_POSTPROCESSING_NONE: {
+ _path_corridor_post_process_nopostprocessing(p_query_task, p_query_task.least_cost_id, begin_poly, begin_point, end_poly, end_point);
+ } break;
+ default: {
+ WARN_PRINT("No match for used PathPostProcessing - fallback to default");
+ _path_corridor_post_process_corridorfunnel(p_query_task, p_query_task.least_cost_id, begin_poly, begin_point, end_poly, end_point, p_map_up);
+ } break;
+ }
- if (r_path_owners) {
- r_path_owners->resize(2);
- r_path_owners->write[0] = begin_poly->owner->get_owner_id();
- r_path_owners->write[1] = end_poly->owner->get_owner_id();
- }
+ p_query_task.path_points.invert();
+ p_query_task.path_meta_point_types.invert();
+ p_query_task.path_meta_point_rids.invert();
+ p_query_task.path_meta_point_owners.invert();
+
+ if (p_query_task.simplify_path) {
+ _query_task_simplified_path_points(p_query_task);
+ }
+
+#ifdef DEBUG_ENABLED
+ // Ensure post conditions as path meta arrays if used MUST match in array size with the path points.
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES)) {
+ DEV_ASSERT(p_query_task.path_points.size() == p_query_task.path_meta_point_types.size());
+ }
- Vector path;
- path.resize(2);
- path.write[0] = begin_point;
- path.write[1] = end_point;
- return path;
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS)) {
+ DEV_ASSERT(p_query_task.path_points.size() == p_query_task.path_meta_point_rids.size());
}
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS)) {
+ DEV_ASSERT(p_query_task.path_points.size() == p_query_task.path_meta_point_owners.size());
+ }
+#endif // DEBUG_ENABLED
+
+ p_query_task.status = NavMeshPathQueryTask3D::TaskStatus::QUERY_FINISHED;
+}
+
+void NavMeshQueries3D::_query_task_build_path_corridor(NavMeshPathQueryTask3D &p_query_task, const LocalVector &p_polygons, const Vector3 &p_map_up, uint32_t p_link_polygons_size, const gd::Polygon *begin_poly, Vector3 begin_point, const gd::Polygon *end_poly, Vector3 end_point) {
// List of all reachable navigation polys.
- LocalVector navigation_polys;
- navigation_polys.resize(p_polygons.size() + p_link_polygons_size);
+ LocalVector &navigation_polys = p_query_task.path_query_slot->path_corridor;
+ for (gd::NavigationPoly &polygon : navigation_polys) {
+ polygon.reset();
+ }
+
+ DEV_ASSERT(navigation_polys.size() == p_polygons.size() + p_link_polygons_size);
// Initialize the matching navigation polygon.
gd::NavigationPoly &begin_navigation_poly = navigation_polys[begin_poly->id];
@@ -218,11 +357,12 @@ Vector NavMeshQueries3D::polygons_get_path(const LocalVector
- traversable_polys;
+ &traversable_polys = p_query_task.path_query_slot->traversable_polys;
+ traversable_polys.clear();
traversable_polys.reserve(p_polygons.size() * 0.25);
// This is an implementation of the A* algorithm.
- int least_cost_id = begin_poly->id;
+ p_query_task.least_cost_id = begin_poly->id;
int prev_least_cost_id = -1;
bool found_route = false;
@@ -232,24 +372,24 @@ Vector NavMeshQueries3D::polygons_get_path(const LocalVectoredges) {
+ for (const gd::Edge &edge : navigation_polys[p_query_task.least_cost_id].poly->edges) {
// Iterate over connections in this edge, then compute the new optimized travel distance assigned to this polygon.
for (uint32_t connection_index = 0; connection_index < edge.connections.size(); connection_index++) {
const gd::Edge::Connection &connection = edge.connections[connection_index];
// Only consider the connection to another polygon if this polygon is in a region with compatible layers.
- if ((p_navigation_layers & connection.polygon->owner->get_navigation_layers()) == 0) {
+ if ((p_query_task.navigation_layers & connection.polygon->owner->get_navigation_layers()) == 0) {
continue;
}
- const gd::NavigationPoly &least_cost_poly = navigation_polys[least_cost_id];
+ const gd::NavigationPoly &least_cost_poly = navigation_polys[p_query_task.least_cost_id];
real_t poly_enter_cost = 0.0;
real_t poly_travel_cost = least_cost_poly.poly->owner->get_travel_cost();
if (prev_least_cost_id != -1 && navigation_polys[prev_least_cost_id].poly->owner->get_self() != least_cost_poly.poly->owner->get_self()) {
poly_enter_cost = least_cost_poly.poly->owner->get_enter_cost();
}
- prev_least_cost_id = least_cost_id;
+ prev_least_cost_id = p_query_task.least_cost_id;
Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end };
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly.entry, pathway);
@@ -262,7 +402,7 @@ Vector NavMeshQueries3D::polygons_get_path(const LocalVector NavMeshQueries3D::polygons_get_path(const LocalVector NavMeshQueries3D::polygons_get_path(const LocalVectorpoints.size(); point_id++) {
Face3 f(end_poly->points[0].pos, end_poly->points[point_id - 1].pos, end_poly->points[point_id].pos);
- Vector3 spoint = f.get_closest_point_to(p_destination);
- real_t dpoint = spoint.distance_to(p_destination);
+ Vector3 spoint = f.get_closest_point_to(p_query_task.target_position);
+ real_t dpoint = spoint.distance_to(p_query_task.target_position);
if (dpoint < end_d) {
end_point = spoint;
end_d = dpoint;
@@ -322,8 +462,8 @@ Vector NavMeshQueries3D::polygons_get_path(const LocalVectorpoints.size(); point_id++) {
Face3 f(begin_poly->points[0].pos, begin_poly->points[point_id - 1].pos, begin_poly->points[point_id].pos);
- Vector3 spoint = f.get_closest_point_to(p_destination);
- real_t dpoint = spoint.distance_to(p_destination);
+ Vector3 spoint = f.get_closest_point_to(p_query_task.target_position);
+ real_t dpoint = spoint.distance_to(p_query_task.target_position);
if (dpoint < end_d) {
end_point = spoint;
end_d = dpoint;
@@ -332,30 +472,8 @@ Vector NavMeshQueries3D::polygons_get_path(const LocalVectorresize(2);
- r_path_types->write[0] = begin_poly->owner->get_type();
- r_path_types->write[1] = begin_poly->owner->get_type();
- }
-
- if (r_path_rids) {
- r_path_rids->resize(2);
- (*r_path_rids)[0] = begin_poly->owner->get_self();
- (*r_path_rids)[1] = begin_poly->owner->get_self();
- }
-
- if (r_path_owners) {
- r_path_owners->resize(2);
- r_path_owners->write[0] = begin_poly->owner->get_owner_id();
- r_path_owners->write[1] = begin_poly->owner->get_owner_id();
- }
-
- Vector path;
- path.resize(2);
- path.write[0] = begin_point;
- path.write[1] = end_point;
- return path;
+ _query_task_create_same_polygon_two_point_path(p_query_task, begin_poly, begin_point, end_poly, end_point);
+ return;
}
for (gd::NavigationPoly &nav_poly : navigation_polys) {
@@ -363,7 +481,7 @@ Vector NavMeshQueries3D::polygons_get_path(const LocalVectorid].poly = begin_poly;
- least_cost_id = begin_poly->id;
+ p_query_task.least_cost_id = begin_poly->id;
prev_least_cost_id = -1;
reachable_end = nullptr;
@@ -372,19 +490,19 @@ Vector NavMeshQueries3D::polygons_get_path(const LocalVectorpoly->id;
+ p_query_task.least_cost_id = traversable_polys.pop()->poly->id;
// Store the farthest reachable end polygon in case our goal is not reachable.
if (is_reachable) {
- real_t distance = navigation_polys[least_cost_id].entry.distance_to(p_destination);
+ real_t distance = navigation_polys[p_query_task.least_cost_id].entry.distance_to(p_query_task.target_position);
if (distance_to_reachable_end > distance) {
distance_to_reachable_end = distance;
- reachable_end = navigation_polys[least_cost_id].poly;
+ reachable_end = navigation_polys[p_query_task.least_cost_id].poly;
}
}
// Check if we reached the end
- if (navigation_polys[least_cost_id].poly == end_poly) {
+ if (navigation_polys[p_query_task.least_cost_id].poly == end_poly) {
found_route = true;
break;
}
@@ -393,190 +511,227 @@ Vector NavMeshQueries3D::polygons_get_path(const LocalVectorpoints.size(); point_id++) {
Face3 f(begin_poly->points[0].pos, begin_poly->points[point_id - 1].pos, begin_poly->points[point_id].pos);
- Vector3 spoint = f.get_closest_point_to(p_destination);
- real_t dpoint = spoint.distance_to(p_destination);
+ Vector3 spoint = f.get_closest_point_to(p_query_task.target_position);
+ real_t dpoint = spoint.distance_to(p_query_task.target_position);
if (dpoint < end_d) {
end_point = spoint;
end_d = dpoint;
}
}
+ _query_task_create_same_polygon_two_point_path(p_query_task, begin_poly, begin_point, begin_poly, end_point);
+ return;
+ }
+}
+
+void NavMeshQueries3D::_query_task_simplified_path_points(NavMeshPathQueryTask3D &p_query_task) {
+ if (!p_query_task.simplify_path || p_query_task.path_points.size() <= 2) {
+ return;
+ }
+
+ const LocalVector &simplified_path_indices = NavMeshQueries3D::get_simplified_path_indices(p_query_task.path_points, p_query_task.simplify_epsilon);
- if (r_path_types) {
- r_path_types->resize(2);
- r_path_types->write[0] = begin_poly->owner->get_type();
- r_path_types->write[1] = begin_poly->owner->get_type();
+ uint32_t index_count = simplified_path_indices.size();
+
+ {
+ Vector3 *points_ptr = p_query_task.path_points.ptr();
+ for (uint32_t i = 0; i < index_count; i++) {
+ points_ptr[i] = points_ptr[simplified_path_indices[i]];
}
+ p_query_task.path_points.resize(index_count);
+ }
- if (r_path_rids) {
- r_path_rids->resize(2);
- (*r_path_rids)[0] = begin_poly->owner->get_self();
- (*r_path_rids)[1] = begin_poly->owner->get_self();
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES)) {
+ int32_t *types_ptr = p_query_task.path_meta_point_types.ptr();
+ for (uint32_t i = 0; i < index_count; i++) {
+ types_ptr[i] = types_ptr[simplified_path_indices[i]];
}
+ p_query_task.path_meta_point_types.resize(index_count);
+ }
- if (r_path_owners) {
- r_path_owners->resize(2);
- r_path_owners->write[0] = begin_poly->owner->get_owner_id();
- r_path_owners->write[1] = begin_poly->owner->get_owner_id();
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS)) {
+ RID *rids_ptr = p_query_task.path_meta_point_rids.ptr();
+ for (uint32_t i = 0; i < index_count; i++) {
+ rids_ptr[i] = rids_ptr[simplified_path_indices[i]];
}
+ p_query_task.path_meta_point_rids.resize(index_count);
+ }
- Vector path;
- path.resize(2);
- path.write[0] = begin_point;
- path.write[1] = end_point;
- return path;
+ if (p_query_task.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS)) {
+ int64_t *owners_ptr = p_query_task.path_meta_point_owners.ptr();
+ for (uint32_t i = 0; i < index_count; i++) {
+ owners_ptr[i] = owners_ptr[simplified_path_indices[i]];
+ }
+ p_query_task.path_meta_point_owners.resize(index_count);
}
+}
- Vector path;
- // Optimize the path.
- if (p_optimize) {
- // Set the apex poly/point to the end point
- gd::NavigationPoly *apex_poly = &navigation_polys[least_cost_id];
+void NavMeshQueries3D::_path_corridor_post_process_corridorfunnel(NavMeshPathQueryTask3D &p_query_task, int p_least_cost_id, const gd::Polygon *p_begin_poly, Vector3 p_begin_point, const gd::Polygon *p_end_polygon, Vector3 p_end_point, const Vector3 &p_map_up) {
+ LocalVector &p_path_corridor = p_query_task.path_query_slot->path_corridor;
- Vector3 back_pathway[2] = { apex_poly->back_navigation_edge_pathway_start, apex_poly->back_navigation_edge_pathway_end };
- const Vector3 back_edge_closest_point = Geometry3D::get_closest_point_to_segment(end_point, back_pathway);
- if (end_point.is_equal_approx(back_edge_closest_point)) {
- // The end point is basically on top of the last crossed edge, funneling around the corners would at best do nothing.
- // At worst it would add an unwanted path point before the last point due to precision issues so skip to the next polygon.
- if (apex_poly->back_navigation_poly_id != -1) {
- apex_poly = &navigation_polys[apex_poly->back_navigation_poly_id];
- }
+ // Set the apex poly/point to the end point
+ gd::NavigationPoly *apex_poly = &p_path_corridor[p_least_cost_id];
+
+ Vector3 back_pathway[2] = { apex_poly->back_navigation_edge_pathway_start, apex_poly->back_navigation_edge_pathway_end };
+ const Vector3 back_edge_closest_point = Geometry3D::get_closest_point_to_segment(p_end_point, back_pathway);
+ if (p_end_point.is_equal_approx(back_edge_closest_point)) {
+ // The end point is basically on top of the last crossed edge, funneling around the corners would at best do nothing.
+ // At worst it would add an unwanted path point before the last point due to precision issues so skip to the next polygon.
+ if (apex_poly->back_navigation_poly_id != -1) {
+ apex_poly = &p_path_corridor[apex_poly->back_navigation_poly_id];
}
+ }
- Vector3 apex_point = end_point;
+ Vector3 apex_point = p_end_point;
- gd::NavigationPoly *left_poly = apex_poly;
- Vector3 left_portal = apex_point;
- gd::NavigationPoly *right_poly = apex_poly;
- Vector3 right_portal = apex_point;
+ gd::NavigationPoly *left_poly = apex_poly;
+ Vector3 left_portal = apex_point;
+ gd::NavigationPoly *right_poly = apex_poly;
+ Vector3 right_portal = apex_point;
- gd::NavigationPoly *p = apex_poly;
+ gd::NavigationPoly *p = apex_poly;
- path.push_back(end_point);
- APPEND_METADATA(end_poly);
+ _query_task_push_back_point_with_metadata(p_query_task, p_end_point, p_end_polygon);
- while (p) {
- // Set left and right points of the pathway between polygons.
- Vector3 left = p->back_navigation_edge_pathway_start;
- Vector3 right = p->back_navigation_edge_pathway_end;
- if (THREE_POINTS_CROSS_PRODUCT(apex_point, left, right).dot(p_map_up) < 0) {
- SWAP(left, right);
- }
+ while (p) {
+ // Set left and right points of the pathway between polygons.
+ Vector3 left = p->back_navigation_edge_pathway_start;
+ Vector3 right = p->back_navigation_edge_pathway_end;
+ if (THREE_POINTS_CROSS_PRODUCT(apex_point, left, right).dot(p_map_up) < 0) {
+ SWAP(left, right);
+ }
- bool skip = false;
- if (THREE_POINTS_CROSS_PRODUCT(apex_point, left_portal, left).dot(p_map_up) >= 0) {
- //process
- if (left_portal == apex_point || THREE_POINTS_CROSS_PRODUCT(apex_point, left, right_portal).dot(p_map_up) > 0) {
- left_poly = p;
- left_portal = left;
- } else {
- clip_path(navigation_polys, path, apex_poly, right_portal, right_poly, r_path_types, r_path_rids, r_path_owners, p_map_up);
-
- apex_point = right_portal;
- p = right_poly;
- left_poly = p;
- apex_poly = p;
- left_portal = apex_point;
- right_portal = apex_point;
-
- path.push_back(apex_point);
- APPEND_METADATA(apex_poly->poly);
- skip = true;
- }
- }
+ bool skip = false;
+ if (THREE_POINTS_CROSS_PRODUCT(apex_point, left_portal, left).dot(p_map_up) >= 0) {
+ //process
+ if (left_portal == apex_point || THREE_POINTS_CROSS_PRODUCT(apex_point, left, right_portal).dot(p_map_up) > 0) {
+ left_poly = p;
+ left_portal = left;
+ } else {
+ clip_path(p_query_task, p_path_corridor, apex_poly, right_portal, right_poly, p_map_up);
- if (!skip && THREE_POINTS_CROSS_PRODUCT(apex_point, right_portal, right).dot(p_map_up) <= 0) {
- //process
- if (right_portal == apex_point || THREE_POINTS_CROSS_PRODUCT(apex_point, right, left_portal).dot(p_map_up) < 0) {
- right_poly = p;
- right_portal = right;
- } else {
- clip_path(navigation_polys, path, apex_poly, left_portal, left_poly, r_path_types, r_path_rids, r_path_owners, p_map_up);
+ apex_point = right_portal;
+ p = right_poly;
+ left_poly = p;
+ apex_poly = p;
+ left_portal = apex_point;
+ right_portal = apex_point;
- apex_point = left_portal;
- p = left_poly;
- right_poly = p;
- apex_poly = p;
- right_portal = apex_point;
- left_portal = apex_point;
+ _query_task_push_back_point_with_metadata(p_query_task, apex_point, apex_poly->poly);
- path.push_back(apex_point);
- APPEND_METADATA(apex_poly->poly);
- }
+ skip = true;
}
+ }
- // Go to the previous polygon.
- if (p->back_navigation_poly_id != -1) {
- p = &navigation_polys[p->back_navigation_poly_id];
+ if (!skip && THREE_POINTS_CROSS_PRODUCT(apex_point, right_portal, right).dot(p_map_up) <= 0) {
+ //process
+ if (right_portal == apex_point || THREE_POINTS_CROSS_PRODUCT(apex_point, right, left_portal).dot(p_map_up) < 0) {
+ right_poly = p;
+ right_portal = right;
} else {
- // The end
- p = nullptr;
+ clip_path(p_query_task, p_path_corridor, apex_poly, left_portal, left_poly, p_map_up);
+
+ apex_point = left_portal;
+ p = left_poly;
+ right_poly = p;
+ apex_poly = p;
+ right_portal = apex_point;
+ left_portal = apex_point;
+
+ _query_task_push_back_point_with_metadata(p_query_task, apex_point, apex_poly->poly);
}
}
- // If the last point is not the begin point, add it to the list.
- if (path[path.size() - 1] != begin_point) {
- path.push_back(begin_point);
- APPEND_METADATA(begin_poly);
+ // Go to the previous polygon.
+ if (p->back_navigation_poly_id != -1) {
+ p = &p_path_corridor[p->back_navigation_poly_id];
+ } else {
+ // The end
+ p = nullptr;
}
+ }
- path.reverse();
- if (r_path_types) {
- r_path_types->reverse();
- }
- if (r_path_rids) {
- r_path_rids->reverse();
- }
- if (r_path_owners) {
- r_path_owners->reverse();
- }
+ // If the last point is not the begin point, add it to the list.
+ if (p_query_task.path_points[p_query_task.path_points.size() - 1] != p_begin_point) {
+ _query_task_push_back_point_with_metadata(p_query_task, p_begin_point, p_begin_poly);
+ }
+}
- } else {
- path.push_back(end_point);
- APPEND_METADATA(end_poly);
-
- // Add mid points
- int np_id = least_cost_id;
- while (np_id != -1 && navigation_polys[np_id].back_navigation_poly_id != -1) {
- if (navigation_polys[np_id].back_navigation_edge != -1) {
- int prev = navigation_polys[np_id].back_navigation_edge;
- int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
- Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
-
- path.push_back(point);
- APPEND_METADATA(navigation_polys[np_id].poly);
- } else {
- path.push_back(navigation_polys[np_id].entry);
- APPEND_METADATA(navigation_polys[np_id].poly);
- }
+void NavMeshQueries3D::_path_corridor_post_process_edgecentered(NavMeshPathQueryTask3D &p_query_task, int p_least_cost_id, const gd::Polygon *p_begin_poly, Vector3 p_begin_point, const gd::Polygon *p_end_polygon, Vector3 p_end_point) {
+ LocalVector &p_path_corridor = p_query_task.path_query_slot->path_corridor;
- np_id = navigation_polys[np_id].back_navigation_poly_id;
- }
+ _query_task_push_back_point_with_metadata(p_query_task, p_end_point, p_end_polygon);
- path.push_back(begin_point);
- APPEND_METADATA(begin_poly);
+ // Add mid points.
+ int np_id = p_least_cost_id;
+ while (np_id != -1 && p_path_corridor[np_id].back_navigation_poly_id != -1) {
+ if (p_path_corridor[np_id].back_navigation_edge != -1) {
+ int prev = p_path_corridor[np_id].back_navigation_edge;
+ int prev_n = (p_path_corridor[np_id].back_navigation_edge + 1) % p_path_corridor[np_id].poly->points.size();
+ Vector3 point = (p_path_corridor[np_id].poly->points[prev].pos + p_path_corridor[np_id].poly->points[prev_n].pos) * 0.5;
- path.reverse();
- if (r_path_types) {
- r_path_types->reverse();
- }
- if (r_path_rids) {
- r_path_rids->reverse();
- }
- if (r_path_owners) {
- r_path_owners->reverse();
+ _query_task_push_back_point_with_metadata(p_query_task, point, p_path_corridor[np_id].poly);
+ } else {
+ _query_task_push_back_point_with_metadata(p_query_task, p_path_corridor[np_id].entry, p_path_corridor[np_id].poly);
}
+
+ np_id = p_path_corridor[np_id].back_navigation_poly_id;
}
- // Ensure post conditions (path arrays MUST match in size).
- CRASH_COND(r_path_types && path.size() != r_path_types->size());
- CRASH_COND(r_path_rids && path.size() != r_path_rids->size());
- CRASH_COND(r_path_owners && path.size() != r_path_owners->size());
+ _query_task_push_back_point_with_metadata(p_query_task, p_begin_point, p_begin_poly);
+}
+
+void NavMeshQueries3D::_path_corridor_post_process_nopostprocessing(NavMeshPathQueryTask3D &p_query_task, int p_least_cost_id, const gd::Polygon *p_begin_poly, Vector3 p_begin_point, const gd::Polygon *p_end_polygon, Vector3 p_end_point) {
+ LocalVector &p_path_corridor = p_query_task.path_query_slot->path_corridor;
- return path;
+ _query_task_push_back_point_with_metadata(p_query_task, p_end_point, p_end_polygon);
+
+ // Add mid points.
+ int np_id = p_least_cost_id;
+ while (np_id != -1 && p_path_corridor[np_id].back_navigation_poly_id != -1) {
+ _query_task_push_back_point_with_metadata(p_query_task, p_path_corridor[np_id].entry, p_path_corridor[np_id].poly);
+
+ np_id = p_path_corridor[np_id].back_navigation_poly_id;
+ }
+
+ _query_task_push_back_point_with_metadata(p_query_task, p_begin_point, p_begin_poly);
+}
+
+void NavMeshQueries3D::_query_task_find_start_end_positions(NavMeshPathQueryTask3D &p_query_task, const LocalVector &p_polygons, const gd::Polygon **r_begin_poly, Vector3 &r_begin_point, const gd::Polygon **r_end_poly, Vector3 &r_end_point) {
+ real_t begin_d = FLT_MAX;
+ real_t end_d = FLT_MAX;
+
+ // Find the initial poly and the end poly on this map.
+ for (const gd::Polygon &p : p_polygons) {
+ // Only consider the polygon if it in a region with compatible layers.
+ if ((p_query_task.navigation_layers & p.owner->get_navigation_layers()) == 0) {
+ continue;
+ }
+
+ // For each face check the distance between the origin/destination.
+ for (size_t point_id = 2; point_id < p.points.size(); point_id++) {
+ const Face3 face(p.points[0].pos, p.points[point_id - 1].pos, p.points[point_id].pos);
+
+ Vector3 point = face.get_closest_point_to(p_query_task.start_position);
+ real_t distance_to_point = point.distance_to(p_query_task.start_position);
+ if (distance_to_point < begin_d) {
+ begin_d = distance_to_point;
+ *r_begin_poly = &p;
+ r_begin_point = point;
+ }
+
+ point = face.get_closest_point_to(p_query_task.target_position);
+ distance_to_point = point.distance_to(p_query_task.target_position);
+ if (distance_to_point < end_d) {
+ end_d = distance_to_point;
+ *r_end_poly = &p;
+ r_end_point = point;
+ }
+ }
+ }
}
Vector3 NavMeshQueries3D::polygons_get_closest_point_to_segment(const LocalVector &p_polygons, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) {
@@ -728,8 +883,8 @@ RID NavMeshQueries3D::polygons_get_closest_point_owner(const LocalVector &p_navigation_polys, Vector &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, Vector *r_path_types, TypedArray *r_path_rids, Vector *r_path_owners, const Vector3 &p_map_up) {
- Vector3 from = path[path.size() - 1];
+void NavMeshQueries3D::clip_path(NavMeshPathQueryTask3D &p_query_task, const LocalVector &p_navigation_polys, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, const Vector3 &p_map_up) {
+ Vector3 from = p_query_task.path_points[p_query_task.path_points.size() - 1];
if (from.is_equal_approx(p_to_point)) {
return;
@@ -753,13 +908,73 @@ void NavMeshQueries3D::clip_path(const LocalVector &p_naviga
if (!pathway_start.is_equal_approx(pathway_end)) {
Vector3 inters;
if (cut_plane.intersects_segment(pathway_start, pathway_end, &inters)) {
- if (!inters.is_equal_approx(p_to_point) && !inters.is_equal_approx(path[path.size() - 1])) {
- path.push_back(inters);
- APPEND_METADATA(from_poly->poly);
+ if (!inters.is_equal_approx(p_to_point) && !inters.is_equal_approx(p_query_task.path_points[p_query_task.path_points.size() - 1])) {
+ _query_task_push_back_point_with_metadata(p_query_task, inters, from_poly->poly);
}
}
}
}
}
+LocalVector NavMeshQueries3D::get_simplified_path_indices(const LocalVector &p_path, real_t p_epsilon) {
+ p_epsilon = MAX(0.0, p_epsilon);
+ real_t squared_epsilon = p_epsilon * p_epsilon;
+
+ LocalVector valid_points;
+ valid_points.resize(p_path.size());
+ for (uint32_t i = 0; i < valid_points.size(); i++) {
+ valid_points[i] = false;
+ }
+
+ simplify_path_segment(0, p_path.size() - 1, p_path, squared_epsilon, valid_points);
+
+ int valid_point_index = 0;
+
+ for (bool valid : valid_points) {
+ if (valid) {
+ valid_point_index += 1;
+ }
+ }
+
+ LocalVector simplified_path_indices;
+ simplified_path_indices.resize(valid_point_index);
+ valid_point_index = 0;
+
+ for (uint32_t i = 0; i < valid_points.size(); i++) {
+ if (valid_points[i]) {
+ simplified_path_indices[valid_point_index] = i;
+ valid_point_index += 1;
+ }
+ }
+
+ return simplified_path_indices;
+}
+
+void NavMeshQueries3D::simplify_path_segment(int p_start_inx, int p_end_inx, const LocalVector &p_points, real_t p_epsilon, LocalVector &r_valid_points) {
+ r_valid_points[p_start_inx] = true;
+ r_valid_points[p_end_inx] = true;
+
+ Vector3 path_segment[2] = { p_points[p_start_inx], p_points[p_end_inx] };
+
+ real_t point_max_distance = 0.0;
+ int point_max_index = 0;
+
+ for (int i = p_start_inx; i < p_end_inx; i++) {
+ const Vector3 &checked_point = p_points[i];
+
+ const Vector3 closest_point = Geometry3D::get_closest_point_to_segment(checked_point, path_segment);
+ real_t distance_squared = closest_point.distance_squared_to(checked_point);
+
+ if (distance_squared > point_max_distance) {
+ point_max_index = i;
+ point_max_distance = distance_squared;
+ }
+ }
+
+ if (point_max_distance > p_epsilon) {
+ simplify_path_segment(p_start_inx, point_max_index, p_points, p_epsilon, r_valid_points);
+ simplify_path_segment(point_max_index, p_end_inx, p_points, p_epsilon, r_valid_points);
+ }
+}
+
#endif // _3D_DISABLED
diff --git a/modules/navigation/3d/nav_mesh_queries_3d.h b/modules/navigation/3d/nav_mesh_queries_3d.h
index 109bb2f97123..a92520f9444e 100644
--- a/modules/navigation/3d/nav_mesh_queries_3d.h
+++ b/modules/navigation/3d/nav_mesh_queries_3d.h
@@ -33,20 +33,91 @@
#ifndef _3D_DISABLED
-#include "../nav_map.h"
+#include "../nav_utils.h"
+
+#include "servers/navigation/navigation_path_query_parameters_3d.h"
+#include "servers/navigation/navigation_path_query_result_3d.h"
+#include "servers/navigation/navigation_utilities.h"
+
+using namespace NavigationUtilities;
+
+class NavMap;
class NavMeshQueries3D {
public:
+ struct PathQuerySlot {
+ LocalVector path_corridor;
+ gd::Heap traversable_polys;
+ bool in_use = false;
+ uint32_t slot_index = 0;
+ };
+
+ struct NavMeshPathQueryTask3D {
+ enum TaskStatus {
+ QUERY_STARTED,
+ QUERY_FINISHED,
+ QUERY_FAILED,
+ CALLBACK_DISPATCHED,
+ CALLBACK_FAILED,
+ };
+
+ // Parameters.
+ Vector3 start_position;
+ Vector3 target_position;
+ uint32_t navigation_layers;
+ BitField metadata_flags = PathMetadataFlags::PATH_INCLUDE_ALL;
+ PathfindingAlgorithm pathfinding_algorithm = PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
+ PathPostProcessing path_postprocessing = PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ bool simplify_path = false;
+ real_t simplify_epsilon = 0.0;
+
+ // Path building.
+ Vector3 begin_position;
+ Vector3 end_position;
+ uint32_t least_cost_id = 0;
+ Vector3 map_up;
+ NavMap *map = nullptr;
+ PathQuerySlot *path_query_slot = nullptr;
+
+ // Path points.
+ LocalVector path_points;
+ LocalVector path_meta_point_types;
+ LocalVector path_meta_point_rids;
+ LocalVector path_meta_point_owners;
+
+ Ref query_parameters;
+ Ref query_result;
+ Callable callback;
+ NavMeshPathQueryTask3D::TaskStatus status = NavMeshPathQueryTask3D::TaskStatus::QUERY_STARTED;
+ };
+
+ static bool emit_callback(const Callable &p_callback);
+
static Vector3 polygons_get_random_point(const LocalVector &p_polygons, uint32_t p_navigation_layers, bool p_uniformly);
- static Vector polygons_get_path(const LocalVector &p_polygons, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector *r_path_types, TypedArray *r_path_rids, Vector *r_path_owners, const Vector3 &p_map_up, uint32_t p_link_polygons_size);
static Vector3 polygons_get_closest_point_to_segment(const LocalVector &p_polygons, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision);
static Vector3 polygons_get_closest_point(const LocalVector &p_polygons, const Vector3 &p_point);
static Vector3 polygons_get_closest_point_normal(const LocalVector &p_polygons, const Vector3 &p_point);
static gd::ClosestPointQueryResult polygons_get_closest_point_info(const LocalVector &p_polygons, const Vector3 &p_point);
static RID polygons_get_closest_point_owner(const LocalVector &p_polygons, const Vector3 &p_point);
- static void clip_path(const LocalVector &p_navigation_polys, Vector &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, Vector *r_path_types, TypedArray *r_path_rids, Vector *r_path_owners, const Vector3 &p_map_up);
+ static void map_query_path(NavMap *map, const Ref &p_query_parameters, Ref p_query_result, const Callable &p_callback);
+
+ static void query_task_polygons_get_path(NavMeshPathQueryTask3D &p_query_task, const LocalVector &p_polygons, const Vector3 &p_map_up, uint32_t p_link_polygons_size);
+
+ static void _query_task_create_same_polygon_two_point_path(NavMeshPathQueryTask3D &p_query_task, const gd::Polygon *begin_poly, Vector3 begin_point, const gd::Polygon *end_poly, Vector3 end_point);
+ static void _query_task_push_back_point_with_metadata(NavMeshPathQueryTask3D &p_query_task, Vector3 p_point, const gd::Polygon *p_point_polygon);
+ static void _query_task_find_start_end_positions(NavMeshPathQueryTask3D &p_query_task, const LocalVector &p_polygons, const gd::Polygon **r_begin_poly, Vector3 &r_begin_point, const gd::Polygon **r_end_poly, Vector3 &r_end_point);
+ static void _query_task_build_path_corridor(NavMeshPathQueryTask3D &p_query_task, const LocalVector &p_polygons, const Vector3 &p_map_up, uint32_t p_link_polygons_size, const gd::Polygon *begin_poly, Vector3 begin_point, const gd::Polygon *end_polygon, Vector3 end_point);
+ static void _path_corridor_post_process_corridorfunnel(NavMeshPathQueryTask3D &p_query_task, int p_least_cost_id, const gd::Polygon *p_begin_poly, Vector3 p_begin_point, const gd::Polygon *p_end_polygon, Vector3 p_end_point, const Vector3 &p_map_up);
+ static void _path_corridor_post_process_edgecentered(NavMeshPathQueryTask3D &p_query_task, int p_least_cost_id, const gd::Polygon *p_begin_poly, Vector3 p_begin_point, const gd::Polygon *p_end_polygon, Vector3 p_end_point);
+ static void _path_corridor_post_process_nopostprocessing(NavMeshPathQueryTask3D &p_query_task, int p_least_cost_id, const gd::Polygon *p_begin_poly, Vector3 p_begin_point, const gd::Polygon *p_end_polygon, Vector3 p_end_point);
+
+ static void clip_path(NavMeshPathQueryTask3D &p_query_task, const LocalVector &p_navigation_polys, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, const Vector3 &p_map_up);
+ static void _query_task_simplified_path_points(NavMeshPathQueryTask3D &p_query_task);
+
+ static void simplify_path_segment(int p_start_inx, int p_end_inx, const LocalVector &p_points, real_t p_epsilon, LocalVector &r_valid_points);
+ static LocalVector get_simplified_path_indices(const LocalVector &p_path, real_t p_epsilon);
};
#endif // _3D_DISABLED
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 739b031d061d..07ee96dc321f 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -35,8 +35,6 @@
#include "nav_obstacle.h"
#include "nav_region.h"
-#include "3d/nav_mesh_queries_3d.h"
-
#include "core/config/project_settings.h"
#include "core/object/worker_thread_pool.h"
@@ -123,16 +121,40 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const {
return p;
}
-Vector NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector *r_path_types, TypedArray *r_path_rids, Vector *r_path_owners) const {
+void NavMap::query_path(NavMeshQueries3D::NavMeshPathQueryTask3D &p_query_task) {
RWLockRead read_lock(map_rwlock);
if (iteration_id == 0) {
- NAVMAP_ITERATION_ZERO_ERROR_MSG();
- return Vector();
+ return;
}
- return NavMeshQueries3D::polygons_get_path(
- polygons, p_origin, p_destination, p_optimize, p_navigation_layers,
- r_path_types, r_path_rids, r_path_owners, up, link_polygons.size());
+ path_query_slots_semaphore.wait();
+
+ path_query_slots_mutex.lock();
+ for (NavMeshQueries3D::PathQuerySlot &p_path_query_slot : path_query_slots) {
+ if (!p_path_query_slot.in_use) {
+ p_path_query_slot.in_use = true;
+ p_query_task.path_query_slot = &p_path_query_slot;
+ break;
+ }
+ }
+ path_query_slots_mutex.unlock();
+
+ if (p_query_task.path_query_slot == nullptr) {
+ path_query_slots_semaphore.post();
+ ERR_FAIL_NULL_MSG(p_query_task.path_query_slot, "No unused NavMap path query slot found! This should never happen :(.");
+ }
+
+ p_query_task.map_up = get_up();
+
+ NavMeshQueries3D::query_task_polygons_get_path(p_query_task, polygons, up, link_polygons.size());
+
+ path_query_slots_mutex.lock();
+ uint32_t used_slot_index = p_query_task.path_query_slot->slot_index;
+ path_query_slots[used_slot_index].in_use = false;
+ p_query_task.path_query_slot = nullptr;
+ path_query_slots_mutex.unlock();
+
+ path_query_slots_semaphore.post();
}
Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
@@ -639,6 +661,15 @@ void NavMap::sync() {
// Some code treats 0 as a failure case, so we avoid returning 0 and modulo wrap UINT32_MAX manually.
iteration_id = iteration_id % UINT32_MAX + 1;
+
+ path_query_slots_mutex.lock();
+ for (NavMeshQueries3D::PathQuerySlot &p_path_query_slot : path_query_slots) {
+ p_path_query_slot.path_corridor.clear();
+ p_path_query_slot.path_corridor.resize(polygons.size() + link_polygons.size());
+ p_path_query_slot.traversable_polys.clear();
+ p_path_query_slot.traversable_polys.reserve(polygons.size() * 0.25);
+ }
+ path_query_slots_mutex.unlock();
}
map_settings_dirty = false;
@@ -969,6 +1000,26 @@ void NavMap::_sync_dirty_avoidance_update_requests() {
NavMap::NavMap() {
avoidance_use_multiple_threads = GLOBAL_GET("navigation/avoidance/thread_model/avoidance_use_multiple_threads");
avoidance_use_high_priority_threads = GLOBAL_GET("navigation/avoidance/thread_model/avoidance_use_high_priority_threads");
+
+ path_query_slots_max = GLOBAL_GET("navigation/pathfinding/max_threads");
+
+ int processor_count = OS::get_singleton()->get_processor_count();
+ if (path_query_slots_max < 0) {
+ path_query_slots_max = processor_count;
+ }
+ if (processor_count < path_query_slots_max) {
+ path_query_slots_max = processor_count;
+ }
+ if (path_query_slots_max < 1) {
+ path_query_slots_max = 1;
+ }
+
+ path_query_slots.resize(path_query_slots_max);
+ for (uint32_t i = 0; i < path_query_slots.size(); i++) {
+ path_query_slots[i].slot_index = i;
+ }
+
+ path_query_slots_semaphore.post(path_query_slots_max);
}
NavMap::~NavMap() {
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index feeb2cc54834..ce247b83c164 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -31,6 +31,7 @@
#ifndef NAV_MAP_H
#define NAV_MAP_H
+#include "3d/nav_mesh_queries_3d.h"
#include "nav_rid.h"
#include "nav_utils.h"
@@ -135,6 +136,11 @@ class NavMap : public NavRid {
SelfList::List obstacles;
} sync_dirty_requests;
+ LocalVector path_query_slots;
+ int path_query_slots_max = 4;
+ Mutex path_query_slots_mutex;
+ Semaphore path_query_slots_semaphore;
+
public:
NavMap();
~NavMap();
@@ -176,7 +182,8 @@ class NavMap : public NavRid {
gd::PointKey get_point_key(const Vector3 &p_pos) const;
- Vector get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector *r_path_types, TypedArray *r_path_rids, Vector *r_path_owners) const;
+ void query_path(NavMeshQueries3D::NavMeshPathQueryTask3D &p_query_task);
+
Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const;
Vector3 get_closest_point(const Vector3 &p_point) const;
Vector3 get_closest_point_normal(const Vector3 &p_point) const;
diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h
index 993a97638dd7..ea22fb0bab3d 100644
--- a/modules/navigation/nav_utils.h
+++ b/modules/navigation/nav_utils.h
@@ -145,6 +145,15 @@ struct NavigationPoly {
bool operator!=(const NavigationPoly &p_other) const {
return !(*this == p_other);
}
+
+ void reset() {
+ poly = nullptr;
+ traversable_poly_index = UINT32_MAX;
+ back_navigation_poly_id = -1;
+ back_navigation_edge = -1;
+ traveled_distance = 0.0;
+ distance_to_destination = 0.0;
+ }
};
struct NavPolyTravelCostGreaterThan {
diff --git a/platform/linuxbsd/wayland/SCsub b/platform/linuxbsd/wayland/SCsub
index f3a554a58db8..c5d8c00c6d77 100644
--- a/platform/linuxbsd/wayland/SCsub
+++ b/platform/linuxbsd/wayland/SCsub
@@ -163,15 +163,25 @@ env.WAYLAND_API_CODE(
)
env.WAYLAND_API_HEADER(
- target="protocol/xdg_foreign.gen.h",
+ target="protocol/xdg_foreign_v1.gen.h",
source="#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml",
)
env.WAYLAND_API_CODE(
- target="protocol/xdg_foreign.gen.c",
+ target="protocol/xdg_foreign_v1.gen.c",
source="#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml",
)
+env.WAYLAND_API_HEADER(
+ target="protocol/xdg_foreign_v2.gen.h",
+ source="#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml",
+)
+
+env.WAYLAND_API_CODE(
+ target="protocol/xdg_foreign_v2.gen.c",
+ source="#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml",
+)
+
env.WAYLAND_API_HEADER(
target="protocol/xdg_system_bell.gen.h",
source="#thirdparty/wayland-protocols/staging/xdg-system-bell/xdg-system-bell-v1.xml",
@@ -188,7 +198,8 @@ source_files = [
"protocol/fractional_scale.gen.c",
"protocol/xdg_shell.gen.c",
"protocol/xdg_system_bell.gen.c",
- "protocol/xdg_foreign.gen.c",
+ "protocol/xdg_foreign_v1.gen.c",
+ "protocol/xdg_foreign_v2.gen.c",
"protocol/xdg_decoration.gen.c",
"protocol/xdg_activation.gen.c",
"protocol/relative_pointer.gen.c",
diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp
index 4eaa932337d2..1130472e9472 100644
--- a/platform/linuxbsd/wayland/wayland_thread.cpp
+++ b/platform/linuxbsd/wayland/wayland_thread.cpp
@@ -377,9 +377,16 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
return;
}
+ // NOTE: Deprecated.
if (strcmp(interface, zxdg_exporter_v1_interface.name) == 0) {
- registry->xdg_exporter = (struct zxdg_exporter_v1 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v1_interface, 1);
- registry->xdg_exporter_name = name;
+ registry->xdg_exporter_v1 = (struct zxdg_exporter_v1 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v1_interface, 1);
+ registry->xdg_exporter_v1_name = name;
+ return;
+ }
+
+ if (strcmp(interface, zxdg_exporter_v2_interface.name) == 0) {
+ registry->xdg_exporter_v2 = (struct zxdg_exporter_v2 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v2_interface, 1);
+ registry->xdg_exporter_v2_name = name;
return;
}
@@ -599,13 +606,25 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
return;
}
- if (name == registry->xdg_exporter_name) {
- if (registry->xdg_exporter) {
- zxdg_exporter_v1_destroy(registry->xdg_exporter);
- registry->xdg_exporter = nullptr;
+ // NOTE: Deprecated.
+ if (name == registry->xdg_exporter_v1_name) {
+ if (registry->xdg_exporter_v1) {
+ zxdg_exporter_v1_destroy(registry->xdg_exporter_v1);
+ registry->xdg_exporter_v1 = nullptr;
+ }
+
+ registry->xdg_exporter_v1_name = 0;
+
+ return;
+ }
+
+ if (name == registry->xdg_exporter_v2_name) {
+ if (registry->xdg_exporter_v2) {
+ zxdg_exporter_v2_destroy(registry->xdg_exporter_v2);
+ registry->xdg_exporter_v2 = nullptr;
}
- registry->xdg_exporter_name = 0;
+ registry->xdg_exporter_v2_name = 0;
return;
}
@@ -1186,7 +1205,15 @@ void WaylandThread::_xdg_toplevel_on_wm_capabilities(void *data, struct xdg_topl
}
}
-void WaylandThread::_xdg_exported_on_exported(void *data, zxdg_exported_v1 *exported, const char *handle) {
+// NOTE: Deprecated.
+void WaylandThread::_xdg_exported_v1_on_handle(void *data, zxdg_exported_v1 *exported, const char *handle) {
+ WindowState *ws = (WindowState *)data;
+ ERR_FAIL_NULL(ws);
+
+ ws->exported_handle = vformat("wayland:%s", String::utf8(handle));
+}
+
+void WaylandThread::_xdg_exported_v2_on_handle(void *data, zxdg_exported_v2 *exported, const char *handle) {
WindowState *ws = (WindowState *)data;
ERR_FAIL_NULL(ws);
@@ -3284,9 +3311,12 @@ void WaylandThread::window_create(DisplayServer::WindowID p_window_id, int p_wid
ws.frame_callback = wl_surface_frame(ws.wl_surface);
wl_callback_add_listener(ws.frame_callback, &frame_wl_callback_listener, &ws);
- if (registry.xdg_exporter) {
- ws.xdg_exported = zxdg_exporter_v1_export(registry.xdg_exporter, ws.wl_surface);
- zxdg_exported_v1_add_listener(ws.xdg_exported, &xdg_exported_listener, &ws);
+ if (registry.xdg_exporter_v2) {
+ ws.xdg_exported_v2 = zxdg_exporter_v2_export_toplevel(registry.xdg_exporter_v2, ws.wl_surface);
+ zxdg_exported_v2_add_listener(ws.xdg_exported_v2, &xdg_exported_v2_listener, &ws);
+ } else if (registry.xdg_exporter_v1) {
+ ws.xdg_exported_v1 = zxdg_exporter_v1_export(registry.xdg_exporter_v1, ws.wl_surface);
+ zxdg_exported_v1_add_listener(ws.xdg_exported_v1, &xdg_exported_v1_listener, &ws);
}
wl_surface_commit(ws.wl_surface);
@@ -4410,10 +4440,14 @@ void WaylandThread::destroy() {
xdg_wm_base_destroy(registry.xdg_wm_base);
}
- if (registry.xdg_exporter) {
- zxdg_exporter_v1_destroy(registry.xdg_exporter);
+ // NOTE: Deprecated.
+ if (registry.xdg_exporter_v1) {
+ zxdg_exporter_v1_destroy(registry.xdg_exporter_v1);
}
+ if (registry.xdg_exporter_v2) {
+ zxdg_exporter_v2_destroy(registry.xdg_exporter_v2);
+ }
if (registry.wl_shm) {
wl_shm_destroy(registry.wl_shm);
}
diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h
index c07694b52ae8..8f1605b82027 100644
--- a/platform/linuxbsd/wayland/wayland_thread.h
+++ b/platform/linuxbsd/wayland/wayland_thread.h
@@ -67,10 +67,13 @@
#include "wayland/protocol/wayland.gen.h"
#include "wayland/protocol/xdg_activation.gen.h"
#include "wayland/protocol/xdg_decoration.gen.h"
-#include "wayland/protocol/xdg_foreign.gen.h"
+#include "wayland/protocol/xdg_foreign_v2.gen.h"
#include "wayland/protocol/xdg_shell.gen.h"
#include "wayland/protocol/xdg_system_bell.gen.h"
+// NOTE: Deprecated.
+#include "wayland/protocol/xdg_foreign_v1.gen.h"
+
#ifdef LIBDECOR_ENABLED
#ifdef SOWRAP_ENABLED
#include "dynwrappers/libdecor-so_wrap.h"
@@ -149,8 +152,12 @@ class WaylandThread {
struct xdg_wm_base *xdg_wm_base = nullptr;
uint32_t xdg_wm_base_name = 0;
- struct zxdg_exporter_v1 *xdg_exporter = nullptr;
- uint32_t xdg_exporter_name = 0;
+ // NOTE: Deprecated.
+ struct zxdg_exporter_v1 *xdg_exporter_v1 = nullptr;
+ uint32_t xdg_exporter_v1_name = 0;
+
+ uint32_t xdg_exporter_v2_name = 0;
+ struct zxdg_exporter_v2 *xdg_exporter_v2 = nullptr;
// wayland-protocols globals.
@@ -224,7 +231,11 @@ class WaylandThread {
struct wp_viewport *wp_viewport = nullptr;
struct wp_fractional_scale_v1 *wp_fractional_scale = nullptr;
- struct zxdg_exported_v1 *xdg_exported = nullptr;
+
+ // NOTE: Deprecated.
+ struct zxdg_exported_v1 *xdg_exported_v1 = nullptr;
+
+ struct zxdg_exported_v2 *xdg_exported_v2 = nullptr;
String exported_handle;
@@ -652,7 +663,10 @@ class WaylandThread {
static void _xdg_toplevel_decoration_on_configure(void *data, struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration, uint32_t mode);
- static void _xdg_exported_on_exported(void *data, zxdg_exported_v1 *exported, const char *handle);
+ // NOTE: Deprecated.
+ static void _xdg_exported_v1_on_handle(void *data, zxdg_exported_v1 *exported, const char *handle);
+
+ static void _xdg_exported_v2_on_handle(void *data, zxdg_exported_v2 *exported, const char *handle);
static void _xdg_activation_token_on_done(void *data, struct xdg_activation_token_v1 *xdg_activation_token, const char *token);
@@ -820,8 +834,13 @@ class WaylandThread {
.done = _wp_text_input_on_done,
};
- static constexpr struct zxdg_exported_v1_listener xdg_exported_listener = {
- .handle = _xdg_exported_on_exported
+ // NOTE: Deprecated.
+ static constexpr struct zxdg_exported_v1_listener xdg_exported_v1_listener = {
+ .handle = _xdg_exported_v1_on_handle,
+ };
+
+ static constexpr struct zxdg_exported_v2_listener xdg_exported_v2_listener = {
+ .handle = _xdg_exported_v2_on_handle,
};
static constexpr struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener = {
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 9f1f7d21e227..9519ca5270a2 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -216,7 +216,7 @@ class DisplayServerMacOS : public DisplayServer {
Callable system_theme_changed;
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect);
- void _update_window_style(WindowData p_wd);
+ void _update_window_style(WindowData p_wd, WindowID p_window);
void _update_displays_arrangement() const;
Point2i _get_native_screen_position(int p_screen) const;
@@ -266,6 +266,8 @@ class DisplayServerMacOS : public DisplayServer {
void mouse_exit_window(WindowID p_window);
void update_presentation_mode();
+ bool is_always_on_top_recursive(WindowID p_window) const;
+
void window_destroy(WindowID p_window);
void window_resize(WindowID p_window, int p_width, int p_height);
void window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled);
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 472d54ae62e1..ee9692f5d74a 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -213,7 +213,7 @@
return id;
}
-void DisplayServerMacOS::_update_window_style(WindowData p_wd) {
+void DisplayServerMacOS::_update_window_style(WindowData p_wd, WindowID p_window) {
bool borderless_full = false;
if (p_wd.borderless) {
@@ -233,7 +233,7 @@
[(NSWindow *)p_wd.window_object setHidesOnDeactivate:YES];
} else {
// Reset these when our window is not a borderless window that covers up the screen.
- if (p_wd.on_top && !p_wd.fullscreen) {
+ if (is_always_on_top_recursive(p_window) && !p_wd.fullscreen) {
[(NSWindow *)p_wd.window_object setLevel:NSFloatingWindowLevel];
} else {
[(NSWindow *)p_wd.window_object setLevel:NSNormalWindowLevel];
@@ -242,6 +242,21 @@
}
}
+bool DisplayServerMacOS::is_always_on_top_recursive(WindowID p_window) const {
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+
+ const WindowData &wd = windows[p_window];
+ if (wd.on_top) {
+ return true;
+ }
+
+ if (wd.transient_parent != INVALID_WINDOW_ID) {
+ return is_always_on_top_recursive(wd.transient_parent);
+ }
+
+ return false;
+}
+
void DisplayServerMacOS::set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window) {
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
@@ -2112,7 +2127,7 @@
[wd.window_object setFrameTopLeftPoint:NSMakePoint(position.x - offset.x, position.y - offset.y)];
- _update_window_style(wd);
+ _update_window_style(wd, p_window);
update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
}
@@ -2250,7 +2265,7 @@
[wd.window_object setFrame:new_frame display:YES];
- _update_window_style(wd);
+ _update_window_style(wd, p_window);
}
Size2i DisplayServerMacOS::window_get_size(WindowID p_window) const {
@@ -2547,7 +2562,7 @@
[wd.window_object setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO];
[wd.window_object setFrame:frameRect display:NO];
}
- _update_window_style(wd);
+ _update_window_style(wd, p_window);
if (was_visible || [wd.window_object isVisible]) {
if ([wd.window_object isMiniaturized]) {
return;
@@ -2632,11 +2647,7 @@
return [wd.window_object styleMask] == NSWindowStyleMaskBorderless;
} break;
case WINDOW_FLAG_ALWAYS_ON_TOP: {
- if (wd.fullscreen) {
- return wd.on_top;
- } else {
- return [(NSWindow *)wd.window_object level] == NSFloatingWindowLevel;
- }
+ return wd.on_top;
} break;
case WINDOW_FLAG_TRANSPARENT: {
return wd.layered_window;
diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm
index 7749debfd6d4..35c053dca5db 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -194,7 +194,7 @@ - (void)windowDidExitFullScreen:(NSNotification *)notification {
}
// Restore on-top state.
- if (wd.on_top) {
+ if (ds->is_always_on_top_recursive(window_id)) {
[wd.window_object setLevel:NSFloatingWindowLevel];
}
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 0769603d8eb2..a0d10549338d 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1606,6 +1606,21 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
return window_id;
}
+bool DisplayServerWindows::_is_always_on_top_recursive(WindowID p_window) const {
+ ERR_FAIL_COND_V(!windows.has(p_window), false);
+
+ const WindowData &wd = windows[p_window];
+ if (wd.always_on_top) {
+ return true;
+ }
+
+ if (wd.transient_parent != INVALID_WINDOW_ID) {
+ return _is_always_on_top_recursive(wd.transient_parent);
+ }
+
+ return false;
+}
+
void DisplayServerWindows::show_window(WindowID p_id) {
ERR_FAIL_COND(!windows.has(p_id));
@@ -1633,7 +1648,7 @@ void DisplayServerWindows::show_window(WindowID p_id) {
SetForegroundWindow(wd.hWnd); // Slightly higher priority.
SetFocus(wd.hWnd); // Set keyboard focus.
}
- if (wd.always_on_top) {
+ if (_is_always_on_top_recursive(p_id)) {
SetWindowPos(wd.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0));
}
}
@@ -2256,7 +2271,7 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain
set_icon(icon);
}
- SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0));
+ SetWindowPos(wd.hWnd, _is_always_on_top_recursive(p_window) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0));
if (p_repaint) {
RECT rect;
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index af5243a14951..52a180984ba0 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -635,6 +635,8 @@ class DisplayServerWindows : public DisplayServer {
void _drag_event(WindowID p_window, float p_x, float p_y, int idx);
void _touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx);
+ bool _is_always_on_top_recursive(WindowID p_window) const;
+
void _update_window_style(WindowID p_window, bool p_repaint = true);
void _update_window_mouse_passthrough(WindowID p_window);
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index f030473c4b74..786598f01a3a 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -133,7 +133,7 @@ void NavigationAgent2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,1000,1,or_greater,suffix:px"), "set_path_max_distance", "get_path_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered,None"), "set_path_postprocessing", "get_path_postprocessing");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_path_metadata_flags", "get_path_metadata_flags");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simplify_path"), "set_simplify_path", "get_simplify_path");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "simplify_epsilon", PROPERTY_HINT_RANGE, "0.0,10.0,0.001,or_greater,suffix:px"), "set_simplify_epsilon", "get_simplify_epsilon");
diff --git a/scene/2d/physics/collision_shape_2d.cpp b/scene/2d/physics/collision_shape_2d.cpp
index bdd0d06b5e2a..a6ddff4563ae 100644
--- a/scene/2d/physics/collision_shape_2d.cpp
+++ b/scene/2d/physics/collision_shape_2d.cpp
@@ -190,7 +190,7 @@ PackedStringArray CollisionShape2D::get_configuration_warnings() const {
Ref convex = shape;
Ref concave = shape;
if (convex.is_valid() || concave.is_valid()) {
- warnings.push_back(RTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead."));
+ warnings.push_back(RTR("The CollisionShape2D node has limited editing options for polygon-based shapes. Consider using a CollisionPolygon2D node instead."));
}
return warnings;
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index faf138896a52..d5e162d41691 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -144,7 +144,7 @@ void NavigationAgent3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,or_greater,suffix:m"), "set_path_max_distance", "get_path_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered,None"), "set_path_postprocessing", "get_path_postprocessing");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_path_metadata_flags", "get_path_metadata_flags");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simplify_path"), "set_simplify_path", "get_simplify_path");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "simplify_epsilon", PROPERTY_HINT_RANGE, "0.0,10.0,0.001,or_greater,suffix:m"), "set_simplify_epsilon", "get_simplify_epsilon");
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index ea0b8cd80864..be54ef7c94ed 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1370,6 +1370,13 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
}
}
// Finish lines and boxes.
+ if (step == DRAW_STEP_BACKGROUND || step == DRAW_STEP_FOREGROUND) {
+ if (last_color.a > 0.0) {
+ Vector2 rect_off = p_ofs + Vector2(box_start - theme_cache.text_highlight_h_padding, off_step.y - l_ascent - theme_cache.text_highlight_v_padding);
+ Vector2 rect_size = Vector2(off_step.x - box_start + 2 * theme_cache.text_highlight_h_padding, l_size.y + 2 * theme_cache.text_highlight_v_padding);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(rect_off, rect_size), last_color);
+ }
+ }
if (step == DRAW_STEP_BACKGROUND) {
if (sel_start != -1) {
Color selection_bg = theme_cache.selection_color;
@@ -1380,13 +1387,6 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
}
}
}
- if (step == DRAW_STEP_BACKGROUND || step == DRAW_STEP_FOREGROUND) {
- if (last_color.a > 0.0) {
- Vector2 rect_off = p_ofs + Vector2(box_start - theme_cache.text_highlight_h_padding, off_step.y - l_ascent - theme_cache.text_highlight_v_padding);
- Vector2 rect_size = Vector2(off_step.x - box_start + 2 * theme_cache.text_highlight_h_padding, l_size.y + 2 * theme_cache.text_highlight_v_padding);
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(rect_off, rect_size), last_color);
- }
- }
if (step == DRAW_STEP_TEXT) {
if (ul_started) {
ul_started = false;
diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
index 41e0aa739ee2..4007cd58e94c 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -197,6 +197,11 @@ void ShaderGlobalsOverride::_get_property_list(List *p_list) const
pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
pinfo.hint_string = "Cubemap";
} break;
+ case RS::GLOBAL_VAR_TYPE_SAMPLEREXT: {
+ pinfo.type = Variant::OBJECT;
+ pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pinfo.hint_string = "ExternalTexture";
+ } break;
default: {
} break;
}
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 1a047dfa2765..06724b461fa5 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1742,6 +1742,11 @@ void Viewport::_gui_input_event(Ref p_event) {
if (mb.is_valid()) {
Point2 mpos = mb->get_position();
if (mb->is_pressed()) {
+ if (gui.dragging && mb->get_button_index() == MouseButton::RIGHT) {
+ _perform_drop();
+ set_input_as_handled();
+ return;
+ }
MouseButtonMask button_mask = mouse_button_to_mask(mb->get_button_index());
if (!gui.mouse_focus_mask.is_empty() && !gui.mouse_focus_mask.has_flag(button_mask)) {
// Do not steal mouse focus and stuff while a focus mask without the current mouse button exists.
diff --git a/scene/resources/compositor.cpp b/scene/resources/compositor.cpp
index 60b7ed0563fa..d9fdb93c5d32 100644
--- a/scene/resources/compositor.cpp
+++ b/scene/resources/compositor.cpp
@@ -85,6 +85,10 @@ void CompositorEffect::_validate_property(PropertyInfo &p_property) const {
}
}
+void CompositorEffect::_call_render_callback(int p_effect_callback_type, const RenderData *p_render_data) {
+ GDVIRTUAL_CALL(_render_callback, p_effect_callback_type, p_render_data);
+}
+
void CompositorEffect::set_enabled(bool p_enabled) {
enabled = p_enabled;
if (rid.is_valid()) {
@@ -105,7 +109,7 @@ void CompositorEffect::set_effect_callback_type(EffectCallbackType p_callback_ty
if (rid.is_valid()) {
RenderingServer *rs = RenderingServer::get_singleton();
ERR_FAIL_NULL(rs);
- rs->compositor_effect_set_callback(rid, RenderingServer::CompositorEffectCallbackType(effect_callback_type), Callable(this, "_render_callback"));
+ rs->compositor_effect_set_callback(rid, RenderingServer::CompositorEffectCallbackType(effect_callback_type), callable_mp(this, &CompositorEffect::_call_render_callback));
}
}
diff --git a/scene/resources/compositor.h b/scene/resources/compositor.h
index ff840c88789f..e7d56878df94 100644
--- a/scene/resources/compositor.h
+++ b/scene/resources/compositor.h
@@ -65,6 +65,8 @@ class CompositorEffect : public Resource {
static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
+ void _call_render_callback(int p_effect_callback_type, const RenderData *p_render_data);
+
GDVIRTUAL2(_render_callback, int, const RenderData *)
public:
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 77ac0569ff35..5cdb7602d47d 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -1515,7 +1515,7 @@ void fragment() {)";
vec3(1.0 + 0.055) * pow(albedo_tex.rgb, vec3(1.0 / 2.4)) - vec3(0.055),
vec3(12.92) * albedo_tex.rgb,
lessThan(albedo_tex.rgb, vec3(0.0031308)));
- vec2 msdf_size = vec2(msdf_pixel_range) / vec2(textureSize(texture_albedo, 0));
+ vec2 msdf_size = vec2(msdf_pixel_range) / vec2(albedo_texture_size));
)";
if (flags[FLAG_USE_POINT_SIZE]) {
code += " vec2 dest_size = vec2(1.0) / fwidth(POINT_COORD);\n";
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index d5c37c2acca4..70f005930bbf 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -352,6 +352,8 @@ void AudioStream::_bind_methods() {
GDVIRTUAL_BIND(_get_bpm)
GDVIRTUAL_BIND(_get_beat_count)
GDVIRTUAL_BIND(_get_parameter_list)
+ GDVIRTUAL_BIND(_has_loop);
+ GDVIRTUAL_BIND(_get_bar_beats);
ADD_SIGNAL(MethodInfo("parameter_list_changed"));
}
diff --git a/servers/navigation/navigation_path_query_parameters_2d.cpp b/servers/navigation/navigation_path_query_parameters_2d.cpp
index 6c1f88e3490c..74aaf64b4e09 100644
--- a/servers/navigation/navigation_path_query_parameters_2d.cpp
+++ b/servers/navigation/navigation_path_query_parameters_2d.cpp
@@ -31,108 +31,75 @@
#include "navigation_path_query_parameters_2d.h"
void NavigationPathQueryParameters2D::set_pathfinding_algorithm(const NavigationPathQueryParameters2D::PathfindingAlgorithm p_pathfinding_algorithm) {
- switch (p_pathfinding_algorithm) {
- case PATHFINDING_ALGORITHM_ASTAR: {
- parameters.pathfinding_algorithm = NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
- } break;
- default: {
- WARN_PRINT_ONCE("No match for used PathfindingAlgorithm - fallback to default");
- parameters.pathfinding_algorithm = NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
- } break;
- }
+ pathfinding_algorithm = p_pathfinding_algorithm;
}
NavigationPathQueryParameters2D::PathfindingAlgorithm NavigationPathQueryParameters2D::get_pathfinding_algorithm() const {
- switch (parameters.pathfinding_algorithm) {
- case NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR:
- return PATHFINDING_ALGORITHM_ASTAR;
- default:
- WARN_PRINT_ONCE("No match for used PathfindingAlgorithm - fallback to default");
- return PATHFINDING_ALGORITHM_ASTAR;
- }
+ return pathfinding_algorithm;
}
void NavigationPathQueryParameters2D::set_path_postprocessing(const NavigationPathQueryParameters2D::PathPostProcessing p_path_postprocessing) {
- switch (p_path_postprocessing) {
- case PATH_POSTPROCESSING_CORRIDORFUNNEL: {
- parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
- } break;
- case PATH_POSTPROCESSING_EDGECENTERED: {
- parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED;
- } break;
- default: {
- WARN_PRINT_ONCE("No match for used PathPostProcessing - fallback to default");
- parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
- } break;
- }
+ path_postprocessing = p_path_postprocessing;
}
NavigationPathQueryParameters2D::PathPostProcessing NavigationPathQueryParameters2D::get_path_postprocessing() const {
- switch (parameters.path_postprocessing) {
- case NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL:
- return PATH_POSTPROCESSING_CORRIDORFUNNEL;
- case NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED:
- return PATH_POSTPROCESSING_EDGECENTERED;
- default:
- WARN_PRINT_ONCE("No match for used PathPostProcessing - fallback to default");
- return PATH_POSTPROCESSING_CORRIDORFUNNEL;
- }
+ return path_postprocessing;
}
-void NavigationPathQueryParameters2D::set_map(const RID &p_map) {
- parameters.map = p_map;
+void NavigationPathQueryParameters2D::set_map(RID p_map) {
+ map = p_map;
}
-const RID &NavigationPathQueryParameters2D::get_map() const {
- return parameters.map;
+RID NavigationPathQueryParameters2D::get_map() const {
+ return map;
}
-void NavigationPathQueryParameters2D::set_start_position(const Vector2 p_start_position) {
- parameters.start_position = Vector3(p_start_position.x, 0.0, p_start_position.y);
+void NavigationPathQueryParameters2D::set_start_position(Vector2 p_start_position) {
+ start_position = p_start_position;
}
Vector2 NavigationPathQueryParameters2D::get_start_position() const {
- return Vector2(parameters.start_position.x, parameters.start_position.z);
+ return start_position;
}
-void NavigationPathQueryParameters2D::set_target_position(const Vector2 p_target_position) {
- parameters.target_position = Vector3(p_target_position.x, 0.0, p_target_position.y);
+void NavigationPathQueryParameters2D::set_target_position(Vector2 p_target_position) {
+ target_position = p_target_position;
}
Vector2 NavigationPathQueryParameters2D::get_target_position() const {
- return Vector2(parameters.target_position.x, parameters.target_position.z);
+ return target_position;
}
void NavigationPathQueryParameters2D::set_navigation_layers(uint32_t p_navigation_layers) {
- parameters.navigation_layers = p_navigation_layers;
+ navigation_layers = p_navigation_layers;
}
uint32_t NavigationPathQueryParameters2D::get_navigation_layers() const {
- return parameters.navigation_layers;
+ return navigation_layers;
}
void NavigationPathQueryParameters2D::set_metadata_flags(BitField p_flags) {
- parameters.metadata_flags = (int64_t)p_flags;
+ metadata_flags = (int64_t)p_flags;
}
BitField NavigationPathQueryParameters2D::get_metadata_flags() const {
- return (int64_t)parameters.metadata_flags;
+ return (int64_t)metadata_flags;
}
void NavigationPathQueryParameters2D::set_simplify_path(bool p_enabled) {
- parameters.simplify_path = p_enabled;
+ simplify_path = p_enabled;
}
bool NavigationPathQueryParameters2D::get_simplify_path() const {
- return parameters.simplify_path;
+ return simplify_path;
}
void NavigationPathQueryParameters2D::set_simplify_epsilon(real_t p_epsilon) {
- parameters.simplify_epsilon = MAX(0.0, p_epsilon);
+ simplify_epsilon = MAX(0.0, p_epsilon);
}
real_t NavigationPathQueryParameters2D::get_simplify_epsilon() const {
- return parameters.simplify_epsilon;
+ return simplify_epsilon;
}
void NavigationPathQueryParameters2D::_bind_methods() {
@@ -168,7 +135,7 @@ void NavigationPathQueryParameters2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position"), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered,None"), "set_path_postprocessing", "get_path_postprocessing");
ADD_PROPERTY(PropertyInfo(Variant::INT, "metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_metadata_flags", "get_metadata_flags");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simplify_path"), "set_simplify_path", "get_simplify_path");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "simplify_epsilon"), "set_simplify_epsilon", "get_simplify_epsilon");
@@ -177,6 +144,7 @@ void NavigationPathQueryParameters2D::_bind_methods() {
BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_CORRIDORFUNNEL);
BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_EDGECENTERED);
+ BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_NONE);
BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_NONE);
BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_TYPES);
diff --git a/servers/navigation/navigation_path_query_parameters_2d.h b/servers/navigation/navigation_path_query_parameters_2d.h
index a1d5f2d109a4..91031bfc180f 100644
--- a/servers/navigation/navigation_path_query_parameters_2d.h
+++ b/servers/navigation/navigation_path_query_parameters_2d.h
@@ -37,19 +37,18 @@
class NavigationPathQueryParameters2D : public RefCounted {
GDCLASS(NavigationPathQueryParameters2D, RefCounted);
- NavigationUtilities::PathQueryParameters parameters;
-
protected:
static void _bind_methods();
public:
enum PathfindingAlgorithm {
- PATHFINDING_ALGORITHM_ASTAR = 0,
+ PATHFINDING_ALGORITHM_ASTAR = NavigationUtilities::PATHFINDING_ALGORITHM_ASTAR,
};
enum PathPostProcessing {
- PATH_POSTPROCESSING_CORRIDORFUNNEL = 0,
- PATH_POSTPROCESSING_EDGECENTERED,
+ PATH_POSTPROCESSING_CORRIDORFUNNEL = NavigationUtilities::PATH_POSTPROCESSING_CORRIDORFUNNEL,
+ PATH_POSTPROCESSING_EDGECENTERED = NavigationUtilities::PATH_POSTPROCESSING_EDGECENTERED,
+ PATH_POSTPROCESSING_NONE = NavigationUtilities::PATH_POSTPROCESSING_NONE,
};
enum PathMetadataFlags {
@@ -60,16 +59,26 @@ class NavigationPathQueryParameters2D : public RefCounted {
PATH_METADATA_INCLUDE_ALL = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_ALL
};
- const NavigationUtilities::PathQueryParameters &get_parameters() const { return parameters; }
+private:
+ PathfindingAlgorithm pathfinding_algorithm = PATHFINDING_ALGORITHM_ASTAR;
+ PathPostProcessing path_postprocessing = PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ RID map;
+ Vector2 start_position;
+ Vector2 target_position;
+ uint32_t navigation_layers = 1;
+ BitField metadata_flags = PATH_METADATA_INCLUDE_ALL;
+ bool simplify_path = false;
+ real_t simplify_epsilon = 0.0;
+public:
void set_pathfinding_algorithm(const PathfindingAlgorithm p_pathfinding_algorithm);
PathfindingAlgorithm get_pathfinding_algorithm() const;
void set_path_postprocessing(const PathPostProcessing p_path_postprocessing);
PathPostProcessing get_path_postprocessing() const;
- void set_map(const RID &p_map);
- const RID &get_map() const;
+ void set_map(RID p_map);
+ RID get_map() const;
void set_start_position(const Vector2 p_start_position);
Vector2 get_start_position() const;
diff --git a/servers/navigation/navigation_path_query_parameters_3d.cpp b/servers/navigation/navigation_path_query_parameters_3d.cpp
index b0a5b0ad82b1..99c5318bed2d 100644
--- a/servers/navigation/navigation_path_query_parameters_3d.cpp
+++ b/servers/navigation/navigation_path_query_parameters_3d.cpp
@@ -31,108 +31,75 @@
#include "navigation_path_query_parameters_3d.h"
void NavigationPathQueryParameters3D::set_pathfinding_algorithm(const NavigationPathQueryParameters3D::PathfindingAlgorithm p_pathfinding_algorithm) {
- switch (p_pathfinding_algorithm) {
- case PATHFINDING_ALGORITHM_ASTAR: {
- parameters.pathfinding_algorithm = NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
- } break;
- default: {
- WARN_PRINT_ONCE("No match for used PathfindingAlgorithm - fallback to default");
- parameters.pathfinding_algorithm = NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
- } break;
- }
+ pathfinding_algorithm = p_pathfinding_algorithm;
}
NavigationPathQueryParameters3D::PathfindingAlgorithm NavigationPathQueryParameters3D::get_pathfinding_algorithm() const {
- switch (parameters.pathfinding_algorithm) {
- case NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR:
- return PATHFINDING_ALGORITHM_ASTAR;
- default:
- WARN_PRINT_ONCE("No match for used PathfindingAlgorithm - fallback to default");
- return PATHFINDING_ALGORITHM_ASTAR;
- }
+ return pathfinding_algorithm;
}
void NavigationPathQueryParameters3D::set_path_postprocessing(const NavigationPathQueryParameters3D::PathPostProcessing p_path_postprocessing) {
- switch (p_path_postprocessing) {
- case PATH_POSTPROCESSING_CORRIDORFUNNEL: {
- parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
- } break;
- case PATH_POSTPROCESSING_EDGECENTERED: {
- parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED;
- } break;
- default: {
- WARN_PRINT_ONCE("No match for used PathPostProcessing - fallback to default");
- parameters.path_postprocessing = NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
- } break;
- }
+ path_postprocessing = p_path_postprocessing;
}
NavigationPathQueryParameters3D::PathPostProcessing NavigationPathQueryParameters3D::get_path_postprocessing() const {
- switch (parameters.path_postprocessing) {
- case NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL:
- return PATH_POSTPROCESSING_CORRIDORFUNNEL;
- case NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED:
- return PATH_POSTPROCESSING_EDGECENTERED;
- default:
- WARN_PRINT_ONCE("No match for used PathPostProcessing - fallback to default");
- return PATH_POSTPROCESSING_CORRIDORFUNNEL;
- }
+ return path_postprocessing;
}
-void NavigationPathQueryParameters3D::set_map(const RID &p_map) {
- parameters.map = p_map;
+void NavigationPathQueryParameters3D::set_map(RID p_map) {
+ map = p_map;
}
-const RID &NavigationPathQueryParameters3D::get_map() const {
- return parameters.map;
+RID NavigationPathQueryParameters3D::get_map() const {
+ return map;
}
-void NavigationPathQueryParameters3D::set_start_position(const Vector3 &p_start_position) {
- parameters.start_position = p_start_position;
+void NavigationPathQueryParameters3D::set_start_position(Vector3 p_start_position) {
+ start_position = p_start_position;
}
-const Vector3 &NavigationPathQueryParameters3D::get_start_position() const {
- return parameters.start_position;
+Vector3 NavigationPathQueryParameters3D::get_start_position() const {
+ return start_position;
}
-void NavigationPathQueryParameters3D::set_target_position(const Vector3 &p_target_position) {
- parameters.target_position = p_target_position;
+void NavigationPathQueryParameters3D::set_target_position(Vector3 p_target_position) {
+ target_position = p_target_position;
}
-const Vector3 &NavigationPathQueryParameters3D::get_target_position() const {
- return parameters.target_position;
+Vector3 NavigationPathQueryParameters3D::get_target_position() const {
+ return target_position;
}
void NavigationPathQueryParameters3D::set_navigation_layers(uint32_t p_navigation_layers) {
- parameters.navigation_layers = p_navigation_layers;
+ navigation_layers = p_navigation_layers;
}
uint32_t NavigationPathQueryParameters3D::get_navigation_layers() const {
- return parameters.navigation_layers;
+ return navigation_layers;
}
void NavigationPathQueryParameters3D::set_metadata_flags(BitField p_flags) {
- parameters.metadata_flags = (int64_t)p_flags;
+ metadata_flags = (int64_t)p_flags;
}
BitField NavigationPathQueryParameters3D::get_metadata_flags() const {
- return (int64_t)parameters.metadata_flags;
+ return (int64_t)metadata_flags;
}
void NavigationPathQueryParameters3D::set_simplify_path(bool p_enabled) {
- parameters.simplify_path = p_enabled;
+ simplify_path = p_enabled;
}
bool NavigationPathQueryParameters3D::get_simplify_path() const {
- return parameters.simplify_path;
+ return simplify_path;
}
void NavigationPathQueryParameters3D::set_simplify_epsilon(real_t p_epsilon) {
- parameters.simplify_epsilon = MAX(0.0, p_epsilon);
+ simplify_epsilon = MAX(0.0, p_epsilon);
}
real_t NavigationPathQueryParameters3D::get_simplify_epsilon() const {
- return parameters.simplify_epsilon;
+ return simplify_epsilon;
}
void NavigationPathQueryParameters3D::_bind_methods() {
@@ -168,7 +135,7 @@ void NavigationPathQueryParameters3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered,None"), "set_path_postprocessing", "get_path_postprocessing");
ADD_PROPERTY(PropertyInfo(Variant::INT, "metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_metadata_flags", "get_metadata_flags");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simplify_path"), "set_simplify_path", "get_simplify_path");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "simplify_epsilon"), "set_simplify_epsilon", "get_simplify_epsilon");
@@ -177,6 +144,7 @@ void NavigationPathQueryParameters3D::_bind_methods() {
BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_CORRIDORFUNNEL);
BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_EDGECENTERED);
+ BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_NONE);
BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_NONE);
BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_TYPES);
diff --git a/servers/navigation/navigation_path_query_parameters_3d.h b/servers/navigation/navigation_path_query_parameters_3d.h
index 2eb85db78757..66cad8dcd543 100644
--- a/servers/navigation/navigation_path_query_parameters_3d.h
+++ b/servers/navigation/navigation_path_query_parameters_3d.h
@@ -37,19 +37,18 @@
class NavigationPathQueryParameters3D : public RefCounted {
GDCLASS(NavigationPathQueryParameters3D, RefCounted);
- NavigationUtilities::PathQueryParameters parameters;
-
protected:
static void _bind_methods();
public:
enum PathfindingAlgorithm {
- PATHFINDING_ALGORITHM_ASTAR = 0,
+ PATHFINDING_ALGORITHM_ASTAR = NavigationUtilities::PATHFINDING_ALGORITHM_ASTAR,
};
enum PathPostProcessing {
- PATH_POSTPROCESSING_CORRIDORFUNNEL = 0,
- PATH_POSTPROCESSING_EDGECENTERED,
+ PATH_POSTPROCESSING_CORRIDORFUNNEL = NavigationUtilities::PATH_POSTPROCESSING_CORRIDORFUNNEL,
+ PATH_POSTPROCESSING_EDGECENTERED = NavigationUtilities::PATH_POSTPROCESSING_EDGECENTERED,
+ PATH_POSTPROCESSING_NONE = NavigationUtilities::PATH_POSTPROCESSING_NONE,
};
enum PathMetadataFlags {
@@ -60,22 +59,32 @@ class NavigationPathQueryParameters3D : public RefCounted {
PATH_METADATA_INCLUDE_ALL = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_ALL
};
- const NavigationUtilities::PathQueryParameters &get_parameters() const { return parameters; }
+private:
+ PathfindingAlgorithm pathfinding_algorithm = PATHFINDING_ALGORITHM_ASTAR;
+ PathPostProcessing path_postprocessing = PATH_POSTPROCESSING_CORRIDORFUNNEL;
+ RID map;
+ Vector3 start_position;
+ Vector3 target_position;
+ uint32_t navigation_layers = 1;
+ BitField metadata_flags = PATH_METADATA_INCLUDE_ALL;
+ bool simplify_path = false;
+ real_t simplify_epsilon = 0.0;
+public:
void set_pathfinding_algorithm(const PathfindingAlgorithm p_pathfinding_algorithm);
PathfindingAlgorithm get_pathfinding_algorithm() const;
void set_path_postprocessing(const PathPostProcessing p_path_postprocessing);
PathPostProcessing get_path_postprocessing() const;
- void set_map(const RID &p_map);
- const RID &get_map() const;
+ void set_map(RID p_map);
+ RID get_map() const;
- void set_start_position(const Vector3 &p_start_position);
- const Vector3 &get_start_position() const;
+ void set_start_position(Vector3 p_start_position);
+ Vector3 get_start_position() const;
- void set_target_position(const Vector3 &p_target_position);
- const Vector3 &get_target_position() const;
+ void set_target_position(Vector3 p_target_position);
+ Vector3 get_target_position() const;
void set_navigation_layers(uint32_t p_navigation_layers);
uint32_t get_navigation_layers() const;
diff --git a/servers/navigation/navigation_path_query_result_2d.h b/servers/navigation/navigation_path_query_result_2d.h
index 856219f998d2..1320d15ea2e1 100644
--- a/servers/navigation/navigation_path_query_result_2d.h
+++ b/servers/navigation/navigation_path_query_result_2d.h
@@ -47,8 +47,8 @@ class NavigationPathQueryResult2D : public RefCounted {
public:
enum PathSegmentType {
- PATH_SEGMENT_TYPE_REGION = 0,
- PATH_SEGMENT_TYPE_LINK = 1,
+ PATH_SEGMENT_TYPE_REGION = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_REGION,
+ PATH_SEGMENT_TYPE_LINK = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_LINK,
};
void set_path(const Vector &p_path);
diff --git a/servers/navigation/navigation_path_query_result_3d.h b/servers/navigation/navigation_path_query_result_3d.h
index fd8545a0c933..8c4e89b9b017 100644
--- a/servers/navigation/navigation_path_query_result_3d.h
+++ b/servers/navigation/navigation_path_query_result_3d.h
@@ -48,8 +48,8 @@ class NavigationPathQueryResult3D : public RefCounted {
public:
enum PathSegmentType {
- PATH_SEGMENT_TYPE_REGION = 0,
- PATH_SEGMENT_TYPE_LINK = 1,
+ PATH_SEGMENT_TYPE_REGION = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_REGION,
+ PATH_SEGMENT_TYPE_LINK = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_LINK,
};
void set_path(const Vector &p_path);
diff --git a/servers/navigation/navigation_utilities.h b/servers/navigation/navigation_utilities.h
index 7ae22b1d3a28..36192c140fc0 100644
--- a/servers/navigation/navigation_utilities.h
+++ b/servers/navigation/navigation_utilities.h
@@ -43,6 +43,7 @@ enum PathfindingAlgorithm {
enum PathPostProcessing {
PATH_POSTPROCESSING_CORRIDORFUNNEL = 0,
PATH_POSTPROCESSING_EDGECENTERED,
+ PATH_POSTPROCESSING_NONE,
};
enum PathSegmentType {
@@ -58,25 +59,6 @@ enum PathMetadataFlags {
PATH_INCLUDE_ALL = PATH_INCLUDE_TYPES | PATH_INCLUDE_RIDS | PATH_INCLUDE_OWNERS
};
-struct PathQueryParameters {
- PathfindingAlgorithm pathfinding_algorithm = PATHFINDING_ALGORITHM_ASTAR;
- PathPostProcessing path_postprocessing = PATH_POSTPROCESSING_CORRIDORFUNNEL;
- RID map;
- Vector3 start_position;
- Vector3 target_position;
- uint32_t navigation_layers = 1;
- BitField metadata_flags = PATH_INCLUDE_ALL;
- bool simplify_path = false;
- real_t simplify_epsilon = 0.0;
-};
-
-struct PathQueryResult {
- PackedVector3Array path;
- PackedInt32Array path_types;
- TypedArray path_rids;
- PackedInt64Array path_owner_ids;
-};
-
} //namespace NavigationUtilities
#endif // NAVIGATION_UTILITIES_H
diff --git a/servers/navigation_server_2d.compat.inc b/servers/navigation_server_2d.compat.inc
new file mode 100644
index 000000000000..14205ef536b0
--- /dev/null
+++ b/servers/navigation_server_2d.compat.inc
@@ -0,0 +1,46 @@
+/**************************************************************************/
+/* navigation_server_2d.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 DISABLE_DEPRECATED
+
+Vector NavigationServer2D::_map_get_path_bind_compat_100129(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers) const {
+ return const_cast(this)->map_get_path(p_map, p_origin, p_destination, p_optimize, p_navigation_layers);
+}
+
+void NavigationServer2D::_query_path_bind_compat_100129(const Ref &p_query_parameters, Ref p_query_result) const {
+ return const_cast(this)->query_path(p_query_parameters, p_query_result, Callable());
+}
+
+void NavigationServer2D::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "navigation_layers"), &NavigationServer2D::_map_get_path_bind_compat_100129, DEFVAL(1));
+ ClassDB::bind_compatibility_method(D_METHOD("query_path", "parameters", "result"), &NavigationServer2D::_query_path_bind_compat_100129);
+}
+
+#endif // DISABLE_DEPRECATED
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index ceb5e909a3b9..cd0dd7e3a042 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "navigation_server_2d.h"
+#include "navigation_server_2d.compat.inc"
#include "servers/navigation_server_3d.h"
@@ -62,7 +63,7 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_random_point", "map", "navigation_layers", "uniformly"), &NavigationServer2D::map_get_random_point);
- ClassDB::bind_method(D_METHOD("query_path", "parameters", "result"), &NavigationServer2D::query_path);
+ ClassDB::bind_method(D_METHOD("query_path", "parameters", "result", "callback"), &NavigationServer2D::query_path, DEFVAL(Callable()));
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
ClassDB::bind_method(D_METHOD("region_set_enabled", "region", "enabled"), &NavigationServer2D::region_set_enabled);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index 250183300f1d..e7c7cf065331 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -91,7 +91,7 @@ class NavigationServer2D : public Object {
virtual real_t map_get_link_connection_radius(RID p_map) const = 0;
/// Returns the navigation path to reach the destination from the origin.
- virtual Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const = 0;
+ virtual Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) = 0;
virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const = 0;
virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const = 0;
@@ -293,7 +293,7 @@ class NavigationServer2D : public Object {
virtual uint32_t obstacle_get_avoidance_layers(RID p_obstacle) const = 0;
/// Returns a customized navigation path using a query parameters object
- virtual void query_path(const Ref &p_query_parameters, Ref p_query_result) const = 0;
+ virtual void query_path(const Ref &p_query_parameters, Ref p_query_result, const Callable &p_callback = Callable()) = 0;
virtual void init() = 0;
virtual void sync() = 0;
@@ -318,6 +318,14 @@ class NavigationServer2D : public Object {
void set_debug_enabled(bool p_enabled);
bool get_debug_enabled() const;
+protected:
+#ifndef DISABLE_DEPRECATED
+ Vector _map_get_path_bind_compat_100129(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const;
+ void _query_path_bind_compat_100129(const Ref &p_query_parameters, Ref p_query_result) const;
+ static void _bind_compatibility_methods();
+#endif
+
+public:
#ifdef DEBUG_ENABLED
void set_debug_navigation_enabled(bool p_enabled);
bool get_debug_navigation_enabled() const;
diff --git a/servers/navigation_server_2d_dummy.h b/servers/navigation_server_2d_dummy.h
index 5bc91830e642..c54e62f80e6d 100644
--- a/servers/navigation_server_2d_dummy.h
+++ b/servers/navigation_server_2d_dummy.h
@@ -50,7 +50,7 @@ class NavigationServer2DDummy : public NavigationServer2D {
real_t map_get_edge_connection_margin(RID p_map) const override { return 0; }
void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) override {}
real_t map_get_link_connection_radius(RID p_map) const override { return 0; }
- Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const override { return Vector(); }
+ Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) override { return Vector(); }
Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const override { return Vector2(); }
RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const override { return RID(); }
TypedArray map_get_links(RID p_map) const override { return TypedArray(); }
@@ -158,7 +158,7 @@ class NavigationServer2DDummy : public NavigationServer2D {
void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override {}
uint32_t obstacle_get_avoidance_layers(RID p_agent) const override { return 0; }
- void query_path(const Ref &p_query_parameters, Ref p_query_result) const override {}
+ void query_path(const Ref &p_query_parameters, Ref p_query_result, const Callable &p_callback = Callable()) override {}
void init() override {}
void sync() override {}
diff --git a/servers/navigation_server_3d.compat.inc b/servers/navigation_server_3d.compat.inc
new file mode 100644
index 000000000000..633e4d5ddff0
--- /dev/null
+++ b/servers/navigation_server_3d.compat.inc
@@ -0,0 +1,46 @@
+/**************************************************************************/
+/* navigation_server_3d.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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 DISABLE_DEPRECATED
+
+Vector NavigationServer3D::_map_get_path_bind_compat_100129(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) const {
+ return const_cast(this)->map_get_path(p_map, p_origin, p_destination, p_optimize, p_navigation_layers);
+}
+
+void NavigationServer3D::_query_path_bind_compat_100129(const Ref &p_query_parameters, Ref p_query_result) const {
+ return const_cast(this)->query_path(p_query_parameters, p_query_result, Callable());
+}
+
+void NavigationServer3D::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "navigation_layers"), &NavigationServer3D::_map_get_path_bind_compat_100129, DEFVAL(1));
+ ClassDB::bind_compatibility_method(D_METHOD("query_path", "parameters", "result"), &NavigationServer3D::_query_path_bind_compat_100129);
+}
+
+#endif // DISABLE_DEPRECATED
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 572309c42963..4c36df83f334 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "navigation_server_3d.h"
+#include "navigation_server_3d.compat.inc"
#include "core/config/project_settings.h"
#include "scene/main/node.h"
@@ -72,7 +73,7 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_random_point", "map", "navigation_layers", "uniformly"), &NavigationServer3D::map_get_random_point);
- ClassDB::bind_method(D_METHOD("query_path", "parameters", "result"), &NavigationServer3D::query_path);
+ ClassDB::bind_method(D_METHOD("query_path", "parameters", "result", "callback"), &NavigationServer3D::query_path, DEFVAL(Callable()));
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create);
ClassDB::bind_method(D_METHOD("region_set_enabled", "region", "enabled"), &NavigationServer3D::region_set_enabled);
@@ -247,6 +248,8 @@ NavigationServer3D::NavigationServer3D() {
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_multiple_threads", true);
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_high_priority_threads", true);
+ GLOBAL_DEF("navigation/pathfinding/max_threads", 4);
+
GLOBAL_DEF("navigation/baking/use_crash_prevention_checks", true);
GLOBAL_DEF("navigation/baking/thread_model/baking_use_multiple_threads", true);
GLOBAL_DEF("navigation/baking/thread_model/baking_use_high_priority_threads", true);
@@ -935,18 +938,6 @@ bool NavigationServer3D::get_debug_avoidance_enabled() const {
#endif // DEBUG_ENABLED
-void NavigationServer3D::query_path(const Ref &p_query_parameters, Ref p_query_result) const {
- ERR_FAIL_COND(!p_query_parameters.is_valid());
- ERR_FAIL_COND(!p_query_result.is_valid());
-
- const NavigationUtilities::PathQueryResult _query_result = _query_path(p_query_parameters->get_parameters());
-
- p_query_result->set_path(_query_result.path);
- p_query_result->set_path_types(_query_result.path_types);
- p_query_result->set_path_rids(_query_result.path_rids);
- p_query_result->set_path_owner_ids(_query_result.path_owner_ids);
-}
-
///////////////////////////////////////////////////////
NavigationServer3DCallback NavigationServer3DManager::create_callback = nullptr;
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index 6dbbd3564810..df5f7658bb2a 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -103,7 +103,7 @@ class NavigationServer3D : public Object {
virtual real_t map_get_link_connection_radius(RID p_map) const = 0;
/// Returns the navigation path to reach the destination from the origin.
- virtual Vector map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const = 0;
+ virtual Vector map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) = 0;
virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const = 0;
virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const = 0;
@@ -343,9 +343,7 @@ class NavigationServer3D : public Object {
virtual void finish() = 0;
/// Returns a customized navigation path using a query parameters object
- virtual void query_path(const Ref &p_query_parameters, Ref p_query_result) const;
-
- virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const = 0;
+ virtual void query_path(const Ref &p_query_parameters, Ref p_query_result, const Callable &p_callback = Callable()) = 0;
#ifndef _3D_DISABLED
virtual void parse_source_geometry_data(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) = 0;
@@ -380,6 +378,13 @@ class NavigationServer3D : public Object {
void set_debug_enabled(bool p_enabled);
bool get_debug_enabled() const;
+protected:
+#ifndef DISABLE_DEPRECATED
+ Vector _map_get_path_bind_compat_100129(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const;
+ void _query_path_bind_compat_100129(const Ref