summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/config/engine.cpp4
-rw-r--r--core/config/engine.h4
-rw-r--r--core/core_bind.cpp14
-rw-r--r--core/core_bind.h4
-rw-r--r--doc/classes/CharacterBody2D.xml3
-rw-r--r--doc/classes/CharacterBody3D.xml3
-rw-r--r--doc/classes/Engine.xml8
-rw-r--r--doc/classes/Node.xml4
-rw-r--r--doc/classes/PhysicsBody2D.xml12
-rw-r--r--doc/classes/PhysicsBody3D.xml12
-rw-r--r--doc/classes/PhysicsServer2D.xml29
-rw-r--r--doc/classes/PhysicsServer3D.xml34
-rw-r--r--doc/classes/ProjectSettings.xml16
-rw-r--r--doc/classes/RayShape2D.xml23
-rw-r--r--doc/classes/RayShape3D.xml23
-rw-r--r--doc/classes/StyleBoxFlat.xml2
-rw-r--r--doc/classes/TextLine.xml18
-rw-r--r--doc/classes/TextParagraph.xml21
-rw-r--r--editor/icons/RayShape2D.svg1
-rw-r--r--editor/icons/RayShape3D.svg1
-rw-r--r--editor/import/resource_importer_scene.cpp6
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp41
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.h1
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp53
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp1
-rw-r--r--main/main.cpp12
-rw-r--r--main/main_timer_sync.cpp16
-rw-r--r--main/main_timer_sync.h6
-rw-r--r--modules/gdnative/text/text_server_gdnative.cpp4
-rw-r--r--modules/gdnative/text/text_server_gdnative.h2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp190
-rw-r--r--modules/text_server_adv/text_server_adv.h3
-rw-r--r--modules/text_server_fb/text_server_fb.cpp133
-rw-r--r--modules/text_server_fb/text_server_fb.h3
-rw-r--r--scene/2d/physics_body_2d.cpp253
-rw-r--r--scene/2d/physics_body_2d.h15
-rw-r--r--scene/3d/collision_shape_3d.cpp7
-rw-r--r--scene/3d/physics_body_3d.cpp137
-rw-r--r--scene/3d/physics_body_3d.h12
-rw-r--r--scene/3d/velocity_tracker_3d.cpp4
-rw-r--r--scene/gui/label.cpp226
-rw-r--r--scene/register_scene_types.cpp5
-rw-r--r--scene/resources/ray_shape_2d.cpp119
-rw-r--r--scene/resources/ray_shape_2d.h61
-rw-r--r--scene/resources/ray_shape_3d.cpp91
-rw-r--r--scene/resources/ray_shape_3d.h56
-rw-r--r--scene/resources/style_box.cpp143
-rw-r--r--scene/resources/style_box.h25
-rw-r--r--scene/resources/text_line.cpp57
-rw-r--r--scene/resources/text_line.h16
-rw-r--r--scene/resources/text_paragraph.cpp314
-rw-r--r--scene/resources/text_paragraph.h26
-rw-r--r--servers/physics_2d/collision_solver_2d_sat.cpp18
-rw-r--r--servers/physics_2d/collision_solver_2d_sw.cpp56
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp20
-rw-r--r--servers/physics_2d/physics_server_2d_sw.h4
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.h10
-rw-r--r--servers/physics_2d/shape_2d_sw.cpp40
-rw-r--r--servers/physics_2d/shape_2d_sw.h35
-rw-r--r--servers/physics_2d/space_2d_sw.cpp223
-rw-r--r--servers/physics_2d/space_2d_sw.h3
-rw-r--r--servers/physics_3d/collision_solver_3d_sat.cpp6
-rw-r--r--servers/physics_3d/collision_solver_3d_sw.cpp47
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp21
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h4
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h10
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp85
-rw-r--r--servers/physics_3d/shape_3d_sw.h28
-rw-r--r--servers/physics_3d/space_3d_sw.cpp187
-rw-r--r--servers/physics_3d/space_3d_sw.h3
-rw-r--r--servers/physics_server_2d.cpp8
-rw-r--r--servers/physics_server_2d.h8
-rw-r--r--servers/physics_server_3d.cpp10
-rw-r--r--servers/physics_server_3d.h20
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl4
-rw-r--r--servers/rendering/shader_language.cpp39
-rw-r--r--servers/text_server.cpp88
-rw-r--r--servers/text_server.h22
78 files changed, 1120 insertions, 2153 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 3ffd8ee46b..495670bc88 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -37,12 +37,12 @@
#include "core/version.h"
#include "core/version_hash.gen.h"
-void Engine::set_iterations_per_second(int p_ips) {
+void Engine::set_physics_ticks_per_second(int p_ips) {
ERR_FAIL_COND_MSG(p_ips <= 0, "Engine iterations per second must be greater than 0.");
ips = p_ips;
}
-int Engine::get_iterations_per_second() const {
+int Engine::get_physics_ticks_per_second() const {
return ips;
}
diff --git a/core/config/engine.h b/core/config/engine.h
index 3b3e5825b2..e6b5df2d5a 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -78,8 +78,8 @@ private:
public:
static Engine *get_singleton();
- virtual void set_iterations_per_second(int p_ips);
- virtual int get_iterations_per_second() const;
+ virtual void set_physics_ticks_per_second(int p_ips);
+ virtual int get_physics_ticks_per_second() const;
void set_physics_jitter_fix(double p_threshold);
double get_physics_jitter_fix() const;
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 76c918a92f..f3f51e57ee 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -2077,12 +2077,12 @@ void _ClassDB::_bind_methods() {
////// _Engine //////
-void _Engine::set_iterations_per_second(int p_ips) {
- Engine::get_singleton()->set_iterations_per_second(p_ips);
+void _Engine::set_physics_ticks_per_second(int p_ips) {
+ Engine::get_singleton()->set_physics_ticks_per_second(p_ips);
}
-int _Engine::get_iterations_per_second() const {
- return Engine::get_singleton()->get_iterations_per_second();
+int _Engine::get_physics_ticks_per_second() const {
+ return Engine::get_singleton()->get_physics_ticks_per_second();
}
void _Engine::set_physics_jitter_fix(double p_threshold) {
@@ -2187,8 +2187,8 @@ bool _Engine::is_printing_error_messages() const {
}
void _Engine::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_iterations_per_second", "iterations_per_second"), &_Engine::set_iterations_per_second);
- ClassDB::bind_method(D_METHOD("get_iterations_per_second"), &_Engine::get_iterations_per_second);
+ ClassDB::bind_method(D_METHOD("set_physics_ticks_per_second", "physics_ticks_per_second"), &_Engine::set_physics_ticks_per_second);
+ ClassDB::bind_method(D_METHOD("get_physics_ticks_per_second"), &_Engine::get_physics_ticks_per_second);
ClassDB::bind_method(D_METHOD("set_physics_jitter_fix", "physics_jitter_fix"), &_Engine::set_physics_jitter_fix);
ClassDB::bind_method(D_METHOD("get_physics_jitter_fix"), &_Engine::get_physics_jitter_fix);
ClassDB::bind_method(D_METHOD("get_physics_interpolation_fraction"), &_Engine::get_physics_interpolation_fraction);
@@ -2225,7 +2225,7 @@ void _Engine::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_hint"), "set_editor_hint", "is_editor_hint");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "iterations_per_second"), "set_iterations_per_second", "get_iterations_per_second");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_ticks_per_second"), "set_physics_ticks_per_second", "get_physics_ticks_per_second");
ADD_PROPERTY(PropertyInfo(Variant::INT, "target_fps"), "set_target_fps", "get_target_fps");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_scale"), "set_time_scale", "get_time_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "physics_jitter_fix"), "set_physics_jitter_fix", "get_physics_jitter_fix");
diff --git a/core/core_bind.h b/core/core_bind.h
index 8736e6ffd8..9060aff340 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -623,8 +623,8 @@ protected:
public:
static _Engine *get_singleton() { return singleton; }
- void set_iterations_per_second(int p_ips);
- int get_iterations_per_second() const;
+ void set_physics_ticks_per_second(int p_ips);
+ int get_physics_ticks_per_second() const;
void set_physics_jitter_fix(double p_threshold);
double get_physics_jitter_fix() const;
diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml
index a6138ee7df..a20b0aeea6 100644
--- a/doc/classes/CharacterBody2D.xml
+++ b/doc/classes/CharacterBody2D.xml
@@ -122,9 +122,6 @@
Sets a snapping distance. When set to a value different from [code]0.0[/code], the body is kept attached to slopes when calling [method move_and_slide]. The snapping vector is determined by the given distance along the opposite direction of the [member up_direction].
As long as the snapping vector is in contact with the ground and the body moves against `up_direction`, the body will remain attached to the surface. Snapping is not applied if the body moves along `up_direction`, so it will be able to detach from the ground when jumping.
</member>
- <member name="infinite_inertia" type="bool" setter="set_infinite_inertia_enabled" getter="is_infinite_inertia_enabled" default="true">
- If [code]true[/code], the body will be able to push [RigidBody2D] nodes when calling [method move_and_slide], but it also won't detect any collisions with them. If [code]false[/code], it will interact with [RigidBody2D] nodes like with [StaticBody2D].
- </member>
<member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector2(0, 0)">
Current velocity vector in pixels per second, used and modified during calls to [method move_and_slide].
</member>
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
index 4cb4f9a850..7dc4ae9be3 100644
--- a/doc/classes/CharacterBody3D.xml
+++ b/doc/classes/CharacterBody3D.xml
@@ -79,9 +79,6 @@
<member name="floor_max_angle" type="float" setter="set_floor_max_angle" getter="get_floor_max_angle" default="0.785398">
Maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. The default value equals 45 degrees.
</member>
- <member name="infinite_inertia" type="bool" setter="set_infinite_inertia_enabled" getter="is_infinite_inertia_enabled" default="true">
- If [code]true[/code], the body will be able to push [RigidBody3D] nodes when calling [method move_and_slide], but it also won't detect any collisions with them. If [code]false[/code], it will interact with [RigidBody3D] nodes like with [StaticBody3D].
- </member>
<member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3(0, 0, 0)">
Current velocity vector (typically meters per second), used and modified during calls to [method move_and_slide].
</member>
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index e4411ab125..886a18900e 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -149,20 +149,20 @@
See [url=https://docs.godotengine.org/en/latest/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information.
[b]Note:[/b] To detect whether the script is run from an editor [i]build[/i] (e.g. when pressing [kbd]F5[/kbd]), use [method OS.has_feature] with the [code]"editor"[/code] argument instead. [code]OS.has_feature("editor")[/code] will evaluate to [code]true[/code] both when the code is running in the editor and when running the project from the editor, but it will evaluate to [code]false[/code] when the code is run from an exported project.
</member>
- <member name="iterations_per_second" type="int" setter="set_iterations_per_second" getter="get_iterations_per_second" default="60">
- The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. This value should generally always be set to [code]60[/code] or above, as Godot doesn't interpolate the physics step. As a result, values lower than [code]60[/code] will look stuttery. This value can be increased to make input more reactive or work around tunneling issues, but keep in mind doing so will increase CPU usage.
- </member>
<member name="physics_jitter_fix" type="float" setter="set_physics_jitter_fix" getter="get_physics_jitter_fix" default="0.5">
Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of the in-game clock and real clock but smooth out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended.
[b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics_jitter_fix] to [code]0[/code].
</member>
+ <member name="physics_ticks_per_second" type="int" setter="set_physics_ticks_per_second" getter="get_physics_ticks_per_second" default="60">
+ The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. This value should generally always be set to [code]60[/code] or above, as Godot doesn't interpolate the physics step. As a result, values lower than [code]60[/code] will look stuttery. This value can be increased to make input more reactive or work around tunneling issues, but keep in mind doing so will increase CPU usage. See also [member target_fps].
+ </member>
<member name="print_error_messages" type="bool" setter="set_print_error_messages" getter="is_printing_error_messages" default="true">
If [code]false[/code], stops printing error and warning messages to the console and editor Output log. This can be used to hide error and warning messages during unit test suite runs. This property is equivalent to the [member ProjectSettings.application/run/disable_stderr] project setting.
[b]Warning:[/b] If you set this to [code]false[/code] anywhere in the project, important error messages may be hidden even if they are emitted from other scripts. If this is set to [code]false[/code] in a [code]@tool[/code] script, this will also impact the editor itself. Do [i]not[/i] report bugs before ensuring error messages are enabled (as they are by default).
[b]Note:[/b] This property does not impact the editor's Errors tab when running a project from the editor.
</member>
<member name="target_fps" type="int" setter="set_target_fps" getter="get_target_fps" default="0">
- The desired frames per second. If the hardware cannot keep up, this setting may not be respected. A value of 0 means no limit.
+ The desired frames per second. If the hardware cannot keep up, this setting may not be respected. A value of 0 means no limit. See also [member physics_ticks_per_second].
</member>
<member name="time_scale" type="float" setter="set_time_scale" getter="get_time_scale" default="1.0">
Controls how fast or slow the in-game clock ticks versus the real life one. It defaults to 1.0. A value of 2.0 means the game moves twice as fast as real life, whilst a value of 0.5 means the game moves at half the regular speed.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 3874046628..096fbbf2c0 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -325,7 +325,7 @@
<method name="get_physics_process_delta_time" qualifiers="const">
<return type="float" />
<description>
- Returns the time elapsed (in seconds) since the last physics-bound frame (see [method _physics_process]). This is always a constant value in physics processing unless the frames per second is changed via [member Engine.iterations_per_second].
+ Returns the time elapsed (in seconds) since the last physics-bound frame (see [method _physics_process]). This is always a constant value in physics processing unless the frames per second is changed via [member Engine.physics_ticks_per_second].
</description>
</method>
<method name="get_process_delta_time" qualifiers="const">
@@ -605,7 +605,7 @@
<return type="void" />
<argument index="0" name="enable" type="bool" />
<description>
- Enables or disables physics (i.e. fixed framerate) processing. When a node is being processed, it will receive a [constant NOTIFICATION_PHYSICS_PROCESS] at a fixed (usually 60 FPS, see [member Engine.iterations_per_second] to change) interval (and the [method _physics_process] callback will be called if exists). Enabled automatically if [method _physics_process] is overridden. Any calls to this before [method _ready] will be ignored.
+ Enables or disables physics (i.e. fixed framerate) processing. When a node is being processed, it will receive a [constant NOTIFICATION_PHYSICS_PROCESS] at a fixed (usually 60 FPS, see [member Engine.physics_ticks_per_second] to change) interval (and the [method _physics_process] callback will be called if exists). Enabled automatically if [method _physics_process] is overridden. Any calls to this before [method _ready] will be ignored.
</description>
</method>
<method name="set_physics_process_internal">
diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index 4d1cd072d0..e00c473bcd 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -26,10 +26,8 @@
<method name="move_and_collide">
<return type="KinematicCollision2D" />
<argument index="0" name="rel_vec" type="Vector2" />
- <argument index="1" name="infinite_inertia" type="bool" default="true" />
- <argument index="2" name="exclude_raycast_shapes" type="bool" default="true" />
- <argument index="3" name="test_only" type="bool" default="false" />
- <argument index="4" name="safe_margin" type="float" default="0.08" />
+ <argument index="1" name="test_only" type="bool" default="false" />
+ <argument index="2" name="safe_margin" type="float" default="0.08" />
<description>
Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision.
If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
@@ -47,10 +45,8 @@
<return type="bool" />
<argument index="0" name="from" type="Transform2D" />
<argument index="1" name="rel_vec" type="Vector2" />
- <argument index="2" name="infinite_inertia" type="bool" default="true" />
- <argument index="3" name="exclude_raycast_shapes" type="bool" default="true" />
- <argument index="4" name="collision" type="KinematicCollision2D" default="null" />
- <argument index="5" name="safe_margin" type="float" default="0.08" />
+ <argument index="2" name="collision" type="KinematicCollision2D" default="null" />
+ <argument index="3" name="safe_margin" type="float" default="0.08" />
<description>
Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
[code]collision[/code] is an optional object of type [KinematicCollision2D], which contains additional information about the collision (should there be one).
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
index a2a68115d0..ea2553e28a 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -33,10 +33,8 @@
<method name="move_and_collide">
<return type="KinematicCollision3D" />
<argument index="0" name="rel_vec" type="Vector3" />
- <argument index="1" name="infinite_inertia" type="bool" default="true" />
- <argument index="2" name="exclude_raycast_shapes" type="bool" default="true" />
- <argument index="3" name="test_only" type="bool" default="false" />
- <argument index="4" name="safe_margin" type="float" default="0.001" />
+ <argument index="1" name="test_only" type="bool" default="false" />
+ <argument index="2" name="safe_margin" type="float" default="0.001" />
<description>
Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision.
If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
@@ -62,10 +60,8 @@
<return type="bool" />
<argument index="0" name="from" type="Transform3D" />
<argument index="1" name="rel_vec" type="Vector3" />
- <argument index="2" name="infinite_inertia" type="bool" default="true" />
- <argument index="3" name="exclude_raycast_shapes" type="bool" default="true" />
- <argument index="4" name="collision" type="KinematicCollision3D" default="null" />
- <argument index="5" name="safe_margin" type="float" default="0.001" />
+ <argument index="2" name="collision" type="KinematicCollision3D" default="null" />
+ <argument index="3" name="safe_margin" type="float" default="0.001" />
<description>
Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
[code]collision[/code] is an optional object of type [KinematicCollision3D], which contains additional information about the collision (should there be one).
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index cf23fecd08..387d79d210 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -593,11 +593,9 @@
<argument index="0" name="body" type="RID" />
<argument index="1" name="from" type="Transform2D" />
<argument index="2" name="motion" type="Vector2" />
- <argument index="3" name="infinite_inertia" type="bool" />
- <argument index="4" name="margin" type="float" default="0.08" />
- <argument index="5" name="result" type="PhysicsTestMotionResult2D" default="null" />
- <argument index="6" name="exclude_raycast_shapes" type="bool" default="true" />
- <argument index="7" name="exclude" type="Array" default="[]" />
+ <argument index="3" name="margin" type="float" default="0.08" />
+ <argument index="4" name="result" type="PhysicsTestMotionResult2D" default="null" />
+ <argument index="5" name="exclude" type="Array" default="[]" />
<description>
Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. Margin increases the size of the shapes involved in the collision detection. [PhysicsTestMotionResult2D] can be passed to return additional information in.
</description>
@@ -723,11 +721,6 @@
<description>
</description>
</method>
- <method name="ray_shape_create">
- <return type="RID" />
- <description>
- </description>
- </method>
<method name="rectangle_shape_create">
<return type="RID" />
<description>
@@ -847,27 +840,25 @@
<constant name="SHAPE_LINE" value="0" enum="ShapeType">
This is the constant for creating line shapes. A line shape is an infinite line with an origin point, and a normal. Thus, it can be used for front/behind checks.
</constant>
- <constant name="SHAPE_RAY" value="1" enum="ShapeType">
- </constant>
- <constant name="SHAPE_SEGMENT" value="2" enum="ShapeType">
+ <constant name="SHAPE_SEGMENT" value="1" enum="ShapeType">
This is the constant for creating segment shapes. A segment shape is a line from a point A to a point B. It can be checked for intersections.
</constant>
- <constant name="SHAPE_CIRCLE" value="3" enum="ShapeType">
+ <constant name="SHAPE_CIRCLE" value="2" enum="ShapeType">
This is the constant for creating circle shapes. A circle shape only has a radius. It can be used for intersections and inside/outside checks.
</constant>
- <constant name="SHAPE_RECTANGLE" value="4" enum="ShapeType">
+ <constant name="SHAPE_RECTANGLE" value="3" enum="ShapeType">
This is the constant for creating rectangle shapes. A rectangle shape is defined by a width and a height. It can be used for intersections and inside/outside checks.
</constant>
- <constant name="SHAPE_CAPSULE" value="5" enum="ShapeType">
+ <constant name="SHAPE_CAPSULE" value="4" enum="ShapeType">
This is the constant for creating capsule shapes. A capsule shape is defined by a radius and a length. It can be used for intersections and inside/outside checks.
</constant>
- <constant name="SHAPE_CONVEX_POLYGON" value="6" enum="ShapeType">
+ <constant name="SHAPE_CONVEX_POLYGON" value="5" enum="ShapeType">
This is the constant for creating convex polygon shapes. A polygon is defined by a list of points. It can be used for intersections and inside/outside checks. Unlike the [member CollisionPolygon2D.polygon] property, polygons modified with [method shape_set_data] do not verify that the points supplied form is a convex polygon.
</constant>
- <constant name="SHAPE_CONCAVE_POLYGON" value="7" enum="ShapeType">
+ <constant name="SHAPE_CONCAVE_POLYGON" value="6" enum="ShapeType">
This is the constant for creating concave polygon shapes. A polygon is defined by a list of points. It can be used for intersections checks, but not for inside/outside checks.
</constant>
- <constant name="SHAPE_CUSTOM" value="8" enum="ShapeType">
+ <constant name="SHAPE_CUSTOM" value="7" enum="ShapeType">
This constant is used internally by the engine. Any attempt to create this kind of shape results in an error.
</constant>
<constant name="AREA_PARAM_GRAVITY" value="0" enum="AreaParameter">
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index d6b7318a06..d46e38ac5f 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -569,11 +569,9 @@
<argument index="0" name="body" type="RID" />
<argument index="1" name="from" type="Transform3D" />
<argument index="2" name="motion" type="Vector3" />
- <argument index="3" name="infinite_inertia" type="bool" />
- <argument index="4" name="margin" type="float" default="0.001" />
- <argument index="5" name="result" type="PhysicsTestMotionResult3D" default="null" />
- <argument index="6" name="exclude_raycast_shapes" type="bool" default="true" />
- <argument index="7" name="exclude" type="Array" default="[]" />
+ <argument index="3" name="margin" type="float" default="0.001" />
+ <argument index="4" name="result" type="PhysicsTestMotionResult3D" default="null" />
+ <argument index="5" name="exclude" type="Array" default="[]" />
<description>
Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. Margin increases the size of the shapes involved in the collision detection. [PhysicsTestMotionResult3D] can be passed to return additional information in.
</description>
@@ -851,11 +849,6 @@
<description>
</description>
</method>
- <method name="ray_shape_create">
- <return type="RID" />
- <description>
- </description>
- </method>
<method name="set_active">
<return type="void" />
<argument index="0" name="active" type="bool" />
@@ -1178,34 +1171,31 @@
<constant name="SHAPE_PLANE" value="0" enum="ShapeType">
The [Shape3D] is a [WorldMarginShape3D].
</constant>
- <constant name="SHAPE_RAY" value="1" enum="ShapeType">
- The [Shape3D] is a [RayShape3D].
- </constant>
- <constant name="SHAPE_SPHERE" value="2" enum="ShapeType">
+ <constant name="SHAPE_SPHERE" value="1" enum="ShapeType">
The [Shape3D] is a [SphereShape3D].
</constant>
- <constant name="SHAPE_BOX" value="3" enum="ShapeType">
+ <constant name="SHAPE_BOX" value="2" enum="ShapeType">
The [Shape3D] is a [BoxShape3D].
</constant>
- <constant name="SHAPE_CAPSULE" value="4" enum="ShapeType">
+ <constant name="SHAPE_CAPSULE" value="3" enum="ShapeType">
The [Shape3D] is a [CapsuleShape3D].
</constant>
- <constant name="SHAPE_CYLINDER" value="5" enum="ShapeType">
+ <constant name="SHAPE_CYLINDER" value="4" enum="ShapeType">
The [Shape3D] is a [CylinderShape3D].
</constant>
- <constant name="SHAPE_CONVEX_POLYGON" value="6" enum="ShapeType">
+ <constant name="SHAPE_CONVEX_POLYGON" value="5" enum="ShapeType">
The [Shape3D] is a [ConvexPolygonShape3D].
</constant>
- <constant name="SHAPE_CONCAVE_POLYGON" value="7" enum="ShapeType">
+ <constant name="SHAPE_CONCAVE_POLYGON" value="6" enum="ShapeType">
The [Shape3D] is a [ConcavePolygonShape3D].
</constant>
- <constant name="SHAPE_HEIGHTMAP" value="8" enum="ShapeType">
+ <constant name="SHAPE_HEIGHTMAP" value="7" enum="ShapeType">
The [Shape3D] is a [HeightMapShape3D].
</constant>
- <constant name="SHAPE_SOFT_BODY" value="9" enum="ShapeType">
+ <constant name="SHAPE_SOFT_BODY" value="8" enum="ShapeType">
The [Shape3D] is a [SoftBody3D].
</constant>
- <constant name="SHAPE_CUSTOM" value="10" enum="ShapeType">
+ <constant name="SHAPE_CUSTOM" value="9" enum="ShapeType">
This constant is used internally by the engine. Any attempt to create this kind of shape results in an error.
</constant>
<constant name="AREA_PARAM_GRAVITY" value="0" enum="AreaParameter">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 6eba469e54..62c2b3295b 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1344,7 +1344,7 @@
</member>
<member name="physics/2d/default_angular_damp" type="float" setter="" getter="" default="1.0">
The default angular damp in 2D.
- [b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_fps], [code]60[/code] by default) will bring the object to a stop in one iteration.
+ [b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_ticks_per_second], [code]60[/code] by default) will bring the object to a stop in one iteration.
</member>
<member name="physics/2d/default_gravity" type="float" setter="" getter="" default="980.0">
The default gravity strength in 2D (in pixels per second squared).
@@ -1376,7 +1376,7 @@
</member>
<member name="physics/2d/default_linear_damp" type="float" setter="" getter="" default="0.1">
The default linear damp in 2D.
- [b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_fps], [code]60[/code] by default) will bring the object to a stop in one iteration.
+ [b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_ticks_per_second], [code]60[/code] by default) will bring the object to a stop in one iteration.
</member>
<member name="physics/2d/physics_engine" type="String" setter="" getter="" default="&quot;DEFAULT&quot;">
Sets which physics engine to use for 2D physics.
@@ -1396,7 +1396,7 @@
</member>
<member name="physics/3d/default_angular_damp" type="float" setter="" getter="" default="0.1">
The default angular damp in 3D.
- [b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_fps], [code]60[/code] by default) will bring the object to a stop in one iteration.
+ [b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_ticks_per_second], [code]60[/code] by default) will bring the object to a stop in one iteration.
</member>
<member name="physics/3d/default_gravity" type="float" setter="" getter="" default="9.8">
The default gravity strength in 3D (in meters per second squared).
@@ -1428,7 +1428,7 @@
</member>
<member name="physics/3d/default_linear_damp" type="float" setter="" getter="" default="0.1">
The default linear damp in 3D.
- [b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_fps], [code]60[/code] by default) will bring the object to a stop in one iteration.
+ [b]Note:[/b] Good values are in the range [code]0[/code] to [code]1[/code]. At value [code]0[/code] objects will keep moving with the same velocity. Values greater than [code]1[/code] will aim to reduce the velocity to [code]0[/code] in less than a second e.g. a value of [code]2[/code] will aim to reduce the velocity to [code]0[/code] in half a second. A value equal to or greater than the physics frame rate ([member ProjectSettings.physics/common/physics_ticks_per_second], [code]60[/code] by default) will bring the object to a stop in one iteration.
</member>
<member name="physics/3d/physics_engine" type="String" setter="" getter="" default="&quot;DEFAULT&quot;">
Sets which physics engine to use for 3D physics.
@@ -1446,15 +1446,15 @@
<member name="physics/common/enable_object_picking" type="bool" setter="" getter="" default="true">
Enables [member Viewport.physics_object_picking] on the root viewport.
</member>
- <member name="physics/common/physics_fps" type="int" setter="" getter="" default="60">
- The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run.
- [b]Note:[/b] This property is only read when the project starts. To change the physics FPS at runtime, set [member Engine.iterations_per_second] instead.
- </member>
<member name="physics/common/physics_jitter_fix" type="float" setter="" getter="" default="0.5">
Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended.
[b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics/common/physics_jitter_fix] to [code]0[/code].
[b]Note:[/b] This property is only read when the project starts. To change the physics FPS at runtime, set [member Engine.physics_jitter_fix] instead.
</member>
+ <member name="physics/common/physics_ticks_per_second" type="int" setter="" getter="" default="60">
+ The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run.
+ [b]Note:[/b] This property is only read when the project starts. To change the physics FPS at runtime, set [member Engine.physics_ticks_per_second] instead.
+ </member>
<member name="rendering/2d/sdf/oversize" type="int" setter="" getter="" default="1">
</member>
<member name="rendering/2d/sdf/scale" type="int" setter="" getter="" default="1">
diff --git a/doc/classes/RayShape2D.xml b/doc/classes/RayShape2D.xml
deleted file mode 100644
index 432c650074..0000000000
--- a/doc/classes/RayShape2D.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RayShape2D" inherits="Shape2D" version="4.0">
- <brief_description>
- Ray shape for 2D collisions.
- </brief_description>
- <description>
- Ray shape for 2D collisions. A ray is not really a collision body; instead, it tries to separate itself from whatever is touching its far endpoint. It's often useful for characters.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="length" type="float" setter="set_length" getter="get_length" default="20.0">
- The ray's length.
- </member>
- <member name="slips_on_slope" type="bool" setter="set_slips_on_slope" getter="get_slips_on_slope" default="false">
- If [code]true[/code], allow the shape to return the correct normal.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/RayShape3D.xml b/doc/classes/RayShape3D.xml
deleted file mode 100644
index 9839044c30..0000000000
--- a/doc/classes/RayShape3D.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RayShape3D" inherits="Shape3D" version="4.0">
- <brief_description>
- Ray shape for 3D collisions.
- </brief_description>
- <description>
- Ray shape for 3D collisions, which can be set into a [PhysicsBody3D] or [Area3D]. A ray is not really a collision body; instead, it tries to separate itself from whatever is touching its far endpoint. It's often useful for characters.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <members>
- <member name="length" type="float" setter="set_length" getter="get_length" default="1.0">
- The ray's length.
- </member>
- <member name="slips_on_slope" type="bool" setter="set_slips_on_slope" getter="get_slips_on_slope" default="false">
- If [code]true[/code], allow the shape to return the correct normal.
- </member>
- </members>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml
index 540b007341..59ab724f48 100644
--- a/doc/classes/StyleBoxFlat.xml
+++ b/doc/classes/StyleBoxFlat.xml
@@ -121,7 +121,7 @@
<member name="anti_aliasing" type="bool" setter="set_anti_aliased" getter="is_anti_aliased" default="true">
Antialiasing draws a small ring around the edges, which fades to transparency. As a result, edges look much smoother. This is only noticeable when using rounded corners.
</member>
- <member name="anti_aliasing_size" type="int" setter="set_aa_size" getter="get_aa_size" default="1">
+ <member name="anti_aliasing_size" type="float" setter="set_aa_size" getter="get_aa_size" default="0.625">
This changes the size of the faded ring. Higher values can be used to achieve a "blurry" effect.
</member>
<member name="bg_color" type="Color" setter="set_bg_color" getter="get_bg_color" default="Color(0.6, 0.6, 0.6, 1)">
diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml
index daa7298418..598d0fb859 100644
--- a/doc/classes/TextLine.xml
+++ b/doc/classes/TextLine.xml
@@ -162,10 +162,28 @@
<member name="preserve_invalid" type="bool" setter="set_preserve_invalid" getter="get_preserve_invalid" default="true">
If set to [code]true[/code] text will display invalid characters.
</member>
+ <member name="text_overrun_behavior" type="int" setter="set_text_overrun_behavior" getter="get_text_overrun_behavior" enum="TextLine.OverrunBehavior" default="3">
+ Sets the clipping behavior when the text exceeds the text line's set width. See [enum OverrunBehavior] for a description of all modes.
+ </member>
<member name="width" type="float" setter="set_width" getter="get_width" default="-1.0">
Text line width.
</member>
</members>
<constants>
+ <constant name="OVERRUN_NO_TRIMMING" value="0" enum="OverrunBehavior">
+ No text trimming is performed.
+ </constant>
+ <constant name="OVERRUN_TRIM_CHAR" value="1" enum="OverrunBehavior">
+ Trims the text per character.
+ </constant>
+ <constant name="OVERRUN_TRIM_WORD" value="2" enum="OverrunBehavior">
+ Trims the text per word.
+ </constant>
+ <constant name="OVERRUN_TRIM_ELLIPSIS" value="3" enum="OverrunBehavior">
+ Trims the text per character and adds an ellipsis to indicate that parts are hidden.
+ </constant>
+ <constant name="OVERRUN_TRIM_WORD_ELLIPSIS" value="4" enum="OverrunBehavior">
+ Trims the text per word and adds an ellipsis to indicate that parts are hidden.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml
index 811fe32eb2..fb94e14c8d 100644
--- a/doc/classes/TextParagraph.xml
+++ b/doc/classes/TextParagraph.xml
@@ -284,6 +284,9 @@
<member name="flags" type="int" setter="set_flags" getter="get_flags" default="51">
Line breaking and alignment rules. For more info see [TextServer].
</member>
+ <member name="max_lines_visible" type="int" setter="set_max_lines_visible" getter="get_max_lines_visible" default="-1">
+ Limits the lines of text shown.
+ </member>
<member name="orientation" type="int" setter="set_orientation" getter="get_orientation" enum="TextServer.Orientation" default="0">
Text orientation.
</member>
@@ -293,10 +296,28 @@
<member name="preserve_invalid" type="bool" setter="set_preserve_invalid" getter="get_preserve_invalid" default="true">
If set to [code]true[/code] text will display invalid characters.
</member>
+ <member name="text_overrun_behavior" type="int" setter="set_text_overrun_behavior" getter="get_text_overrun_behavior" enum="TextParagraph.OverrunBehavior" default="0">
+ Sets the clipping behavior when the text exceeds the paragraph's set width. See [enum OverrunBehavior] for a description of all modes.
+ </member>
<member name="width" type="float" setter="set_width" getter="get_width" default="-1.0">
Paragraph width.
</member>
</members>
<constants>
+ <constant name="OVERRUN_NO_TRIMMING" value="0" enum="OverrunBehavior">
+ No text trimming is performed.
+ </constant>
+ <constant name="OVERRUN_TRIM_CHAR" value="1" enum="OverrunBehavior">
+ Trims the text per character.
+ </constant>
+ <constant name="OVERRUN_TRIM_WORD" value="2" enum="OverrunBehavior">
+ Trims the text per word.
+ </constant>
+ <constant name="OVERRUN_TRIM_ELLIPSIS" value="3" enum="OverrunBehavior">
+ Trims the text per character and adds an ellipsis to indicate that parts are hidden.
+ </constant>
+ <constant name="OVERRUN_TRIM_WORD_ELLIPSIS" value="4" enum="OverrunBehavior">
+ Trims the text per word and adds an ellipsis to indicate that parts are hidden.
+ </constant>
</constants>
</class>
diff --git a/editor/icons/RayShape2D.svg b/editor/icons/RayShape2D.svg
deleted file mode 100644
index aa8cee1210..0000000000
--- a/editor/icons/RayShape2D.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a1 1 0 0 0 -1 1v9.5859l-1.293-1.293a1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l3 3a1.0001 1.0001 0 0 0 .0039062.003907 1 1 0 0 0 .050781.044921 1.0001 1.0001 0 0 0 .03125.027344 1 1 0 0 0 .048828.035156 1.0001 1.0001 0 0 0 .023438.015625 1 1 0 0 0 .076172.044922 1.0001 1.0001 0 0 0 .0058593.003906 1 1 0 0 0 .013672.007813 1.0001 1.0001 0 0 0 .078125.035156 1 1 0 0 0 .074219.025391 1.0001 1.0001 0 0 0 .025391.009766 1 1 0 0 0 .039062.009765 1.0001 1.0001 0 0 0 .068359.013672 1.0001 1.0001 0 0 0 .097656.011719 1.0001 1.0001 0 0 0 .0078125 0 1 1 0 0 0 .0625.003906 1 1 0 0 0 .015625-.001953 1.0001 1.0001 0 0 0 .083984-.003906 1 1 0 0 0 .015625-.001953 1.0001 1.0001 0 0 0 .083984-.013672 1.0001 1.0001 0 0 0 .052734-.013672 1 1 0 0 0 .058594-.015625 1.0001 1.0001 0 0 0 .078125-.029297 1 1 0 0 0 .013672-.00586 1.0001 1.0001 0 0 0 .076172-.037109 1 1 0 0 0 .013672-.007812 1.0001 1.0001 0 0 0 .072266-.044922 1 1 0 0 0 .011719-.007813 1.0001 1.0001 0 0 0 .068359-.052734 1 1 0 0 0 .011719-.009766 1.0001 1.0001 0 0 0 .050781-.046875l.0097657-.011719 2.9902-2.9883a1 1 0 0 0 0-1.4141 1 1 0 0 0 -1.4141 0l-1.293 1.293v-9.5859a1 1 0 0 0 -1-1z" fill="#68b6ff" fill-rule="evenodd"/></svg>
diff --git a/editor/icons/RayShape3D.svg b/editor/icons/RayShape3D.svg
deleted file mode 100644
index 44d32fe83b..0000000000
--- a/editor/icons/RayShape3D.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="m8 1-6 5 4 2.666v4.334l2 2v-5-2z" fill="#a2d2ff"/><path d="m8 1v7 2l-2-1.334v1.334l2 1.5v3.5l2-2v-4.334l4-2.666z" fill="#2998ff"/></g></svg>
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 50aae6c434..492fa3f965 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -45,7 +45,6 @@
#include "scene/resources/animation.h"
#include "scene/resources/box_shape_3d.h"
#include "scene/resources/packed_scene.h"
-#include "scene/resources/ray_shape_3d.h"
#include "scene/resources/resource_format_text.h"
#include "scene/resources/sphere_shape_3d.h"
#include "scene/resources/surface_tool.h"
@@ -381,11 +380,6 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
BoxShape3D *boxShape = memnew(BoxShape3D);
boxShape->set_size(Vector3(2, 2, 2));
colshape->set_shape(boxShape);
- } else if (empty_draw_type == "SINGLE_ARROW") {
- RayShape3D *rayShape = memnew(RayShape3D);
- rayShape->set_length(1);
- colshape->set_shape(rayShape);
- Object::cast_to<Node3D>(sb)->rotate_x(Math_PI / 2);
} else if (empty_draw_type == "IMAGE") {
WorldMarginShape3D *world_margin_shape = memnew(WorldMarginShape3D);
colshape->set_shape(world_margin_shape);
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 2c2adc2672..5a6b7d98d3 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -37,7 +37,6 @@
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/line_shape_2d.h"
-#include "scene/resources/ray_shape_2d.h"
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/segment_shape_2d.h"
@@ -86,15 +85,6 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const {
} break;
- case RAY_SHAPE: {
- Ref<RayShape2D> ray = node->get_shape();
-
- if (idx == 0) {
- return ray->get_length();
- }
-
- } break;
-
case RECTANGLE_SHAPE: {
Ref<RectangleShape2D> rect = node->get_shape();
@@ -167,15 +157,6 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
} break;
- case RAY_SHAPE: {
- Ref<RayShape2D> ray = node->get_shape();
-
- ray->set_length(Math::abs(p_point.y));
-
- canvas_item_editor->update_viewport();
-
- } break;
-
case RECTANGLE_SHAPE: {
if (idx < 8) {
Ref<RectangleShape2D> rect = node->get_shape();
@@ -277,16 +258,6 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
} break;
- case RAY_SHAPE: {
- Ref<RayShape2D> ray = node->get_shape();
-
- undo_redo->add_do_method(ray.ptr(), "set_length", ray->get_length());
- undo_redo->add_do_method(canvas_item_editor, "update_viewport");
- undo_redo->add_undo_method(ray.ptr(), "set_length", p_org);
- undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
-
- } break;
-
case RECTANGLE_SHAPE: {
Ref<RectangleShape2D> rect = node->get_shape();
@@ -428,8 +399,6 @@ void CollisionShape2DEditor::_get_current_shape_type() {
shape_type = CONVEX_POLYGON_SHAPE;
} else if (Object::cast_to<LineShape2D>(*s)) {
shape_type = LINE_SHAPE;
- } else if (Object::cast_to<RayShape2D>(*s)) {
- shape_type = RAY_SHAPE;
} else if (Object::cast_to<RectangleShape2D>(*s)) {
shape_type = RECTANGLE_SHAPE;
} else if (Object::cast_to<SegmentShape2D>(*s)) {
@@ -507,16 +476,6 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla
} break;
- case RAY_SHAPE: {
- Ref<RayShape2D> shape = node->get_shape();
-
- handles.resize(1);
- handles.write[0] = Point2(0, shape->get_length());
-
- p_overlay->draw_texture(h, gt.xform(handles[0]) - size);
-
- } break;
-
case RECTANGLE_SHAPE: {
Ref<RectangleShape2D> shape = node->get_shape();
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h
index 7db6bd22aa..130ec708cf 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.h
+++ b/editor/plugins/collision_shape_2d_editor_plugin.h
@@ -47,7 +47,6 @@ class CollisionShape2DEditor : public Control {
CONCAVE_POLYGON_SHAPE,
CONVEX_POLYGON_SHAPE,
LINE_SHAPE,
- RAY_SHAPE,
RECTANGLE_SHAPE,
SEGMENT_SHAPE
};
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index b8cbaaf7c1..8b098ad23b 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -66,7 +66,6 @@
#include "scene/resources/cylinder_shape_3d.h"
#include "scene/resources/height_map_shape_3d.h"
#include "scene/resources/primitive_meshes.h"
-#include "scene/resources/ray_shape_3d.h"
#include "scene/resources/sphere_shape_3d.h"
#include "scene/resources/surface_tool.h"
#include "scene/resources/world_margin_shape_3d.h"
@@ -4081,10 +4080,6 @@ String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g
return p_id == 0 ? "Radius" : "Height";
}
- if (Object::cast_to<RayShape3D>(*s)) {
- return "Length";
- }
-
return "";
}
@@ -4116,11 +4111,6 @@ Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p
return p_id == 0 ? cs2->get_radius() : cs2->get_height();
}
- if (Object::cast_to<RayShape3D>(*s)) {
- Ref<RayShape3D> cs2 = s;
- return cs2->get_length();
- }
-
return Variant();
}
@@ -4156,22 +4146,6 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
ss->set_radius(d);
}
- if (Object::cast_to<RayShape3D>(*s)) {
- Ref<RayShape3D> rs = s;
- Vector3 ra, rb;
- Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(0, 0, 4096), sg[0], sg[1], ra, rb);
- float d = ra.z;
- if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001) {
- d = 0.001;
- }
-
- rs->set_length(d);
- }
-
if (Object::cast_to<BoxShape3D>(*s)) {
Vector3 axis;
axis[p_id] = 1.0;
@@ -4330,20 +4304,6 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
ur->commit_action();
}
-
- if (Object::cast_to<RayShape3D>(*s)) {
- Ref<RayShape3D> ss = s;
- if (p_cancel) {
- ss->set_length(p_restore);
- return;
- }
-
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Ray Shape Length"));
- ur->add_do_method(ss.ptr(), "set_length", ss->get_length());
- ur->add_undo_method(ss.ptr(), "set_length", p_restore);
- ur->commit_action();
- }
}
void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
@@ -4614,19 +4574,6 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_segments(cs2->get_debug_mesh_lines());
}
- if (Object::cast_to<RayShape3D>(*s)) {
- Ref<RayShape3D> rs = s;
-
- Vector<Vector3> points;
- points.push_back(Vector3());
- points.push_back(Vector3(0, 0, rs->get_length()));
- p_gizmo->add_lines(points, material);
- p_gizmo->add_collision_segments(points);
- Vector<Vector3> handles;
- handles.push_back(Vector3(0, 0, rs->get_length()));
- p_gizmo->add_handles(handles, handles_material);
- }
-
if (Object::cast_to<HeightMapShape3D>(*s)) {
Ref<HeightMapShape3D> hms = s;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index f960da6732..038ce1467e 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -2361,6 +2361,7 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa
position += graph->get_size() * 0.5;
position /= EDSCALE;
}
+ position /= graph->get_zoom();
saved_node_pos_dirty = false;
int id_to_use = visual_shader->get_valid_node_id(type);
diff --git a/main/main.cpp b/main/main.cpp
index d91cc5c9bf..f899894642 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1340,9 +1340,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
{
window_vsync_mode = DisplayServer::VSyncMode(int(GLOBAL_DEF("display/window/vsync/vsync_mode", DisplayServer::VSyncMode::VSYNC_ENABLED)));
}
- Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF_BASIC("physics/common/physics_fps", 60));
- ProjectSettings::get_singleton()->set_custom_property_info("physics/common/physics_fps",
- PropertyInfo(Variant::INT, "physics/common/physics_fps",
+ Engine::get_singleton()->set_physics_ticks_per_second(GLOBAL_DEF_BASIC("physics/common/physics_ticks_per_second", 60));
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/common/physics_ticks_per_second",
+ PropertyInfo(Variant::INT, "physics/common/physics_ticks_per_second",
PROPERTY_HINT_RANGE, "1,1000,1"));
Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/settings/fps/force_fps", 0));
@@ -2463,12 +2463,12 @@ bool Main::iteration() {
uint64_t ticks_elapsed = ticks - last_ticks;
- int physics_fps = Engine::get_singleton()->get_iterations_per_second();
- float physics_step = 1.0 / physics_fps;
+ int physics_ticks_per_second = Engine::get_singleton()->get_physics_ticks_per_second();
+ float physics_step = 1.0 / physics_ticks_per_second;
float time_scale = Engine::get_singleton()->get_time_scale();
- MainFrameTime advance = main_timer_sync.advance(physics_step, physics_fps);
+ MainFrameTime advance = main_timer_sync.advance(physics_step, physics_ticks_per_second);
double process_step = advance.process_step;
double scaled_step = process_step * time_scale;
diff --git a/main/main_timer_sync.cpp b/main/main_timer_sync.cpp
index 94e62bea97..0d172be65e 100644
--- a/main/main_timer_sync.cpp
+++ b/main/main_timer_sync.cpp
@@ -73,14 +73,14 @@ int MainTimerSync::get_average_physics_steps(double &p_min, double &p_max) {
}
// advance physics clock by p_process_step, return appropriate number of steps to simulate
-MainFrameTime MainTimerSync::advance_core(double p_physics_step, int p_physics_fps, double p_process_step) {
+MainFrameTime MainTimerSync::advance_core(double p_physics_step, int p_physics_ticks_per_second, double p_process_step) {
MainFrameTime ret;
ret.process_step = p_process_step;
// simple determination of number of physics iteration
time_accum += ret.process_step;
- ret.physics_steps = floor(time_accum * p_physics_fps);
+ ret.physics_steps = floor(time_accum * p_physics_ticks_per_second);
int min_typical_steps = typical_physics_steps[0];
int max_typical_steps = min_typical_steps + 1;
@@ -107,7 +107,7 @@ MainFrameTime MainTimerSync::advance_core(double p_physics_step, int p_physics_f
// try to keep it consistent with previous iterations
if (ret.physics_steps < min_typical_steps) {
- const int max_possible_steps = floor((time_accum)*p_physics_fps + get_physics_jitter_fix());
+ const int max_possible_steps = floor((time_accum)*p_physics_ticks_per_second + get_physics_jitter_fix());
if (max_possible_steps < min_typical_steps) {
ret.physics_steps = max_possible_steps;
update_typical = true;
@@ -115,7 +115,7 @@ MainFrameTime MainTimerSync::advance_core(double p_physics_step, int p_physics_f
ret.physics_steps = min_typical_steps;
}
} else if (ret.physics_steps > max_typical_steps) {
- const int min_possible_steps = floor((time_accum)*p_physics_fps - get_physics_jitter_fix());
+ const int min_possible_steps = floor((time_accum)*p_physics_ticks_per_second - get_physics_jitter_fix());
if (min_possible_steps > max_typical_steps) {
ret.physics_steps = min_possible_steps;
update_typical = true;
@@ -146,7 +146,7 @@ MainFrameTime MainTimerSync::advance_core(double p_physics_step, int p_physics_f
}
// calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero
-MainFrameTime MainTimerSync::advance_checked(double p_physics_step, int p_physics_fps, double p_process_step) {
+MainFrameTime MainTimerSync::advance_checked(double p_physics_step, int p_physics_ticks_per_second, double p_process_step) {
if (fixed_fps != -1) {
p_process_step = 1.0 / fixed_fps;
}
@@ -154,7 +154,7 @@ MainFrameTime MainTimerSync::advance_checked(double p_physics_step, int p_physic
// compensate for last deficit
p_process_step += time_deficit;
- MainFrameTime ret = advance_core(p_physics_step, p_physics_fps, p_process_step);
+ MainFrameTime ret = advance_core(p_physics_step, p_physics_ticks_per_second, p_process_step);
// we will do some clamping on ret.process_step and need to sync those changes to time_accum,
// that's easiest if we just remember their fixed difference now
@@ -220,8 +220,8 @@ void MainTimerSync::set_fixed_fps(int p_fixed_fps) {
}
// advance one physics frame, return timesteps to take
-MainFrameTime MainTimerSync::advance(double p_physics_step, int p_physics_fps) {
+MainFrameTime MainTimerSync::advance(double p_physics_step, int p_physics_ticks_per_second) {
double cpu_process_step = get_cpu_process_step();
- return advance_checked(p_physics_step, p_physics_fps, cpu_process_step);
+ return advance_checked(p_physics_step, p_physics_ticks_per_second, cpu_process_step);
}
diff --git a/main/main_timer_sync.h b/main/main_timer_sync.h
index abdec18f6d..d0ebcb8f96 100644
--- a/main/main_timer_sync.h
+++ b/main/main_timer_sync.h
@@ -77,10 +77,10 @@ protected:
int get_average_physics_steps(double &p_min, double &p_max);
// advance physics clock by p_process_step, return appropriate number of steps to simulate
- MainFrameTime advance_core(double p_physics_step, int p_physics_fps, double p_process_step);
+ MainFrameTime advance_core(double p_physics_step, int p_physics_ticks_per_second, double p_process_step);
// calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero
- MainFrameTime advance_checked(double p_physics_step, int p_physics_fps, double p_process_step);
+ MainFrameTime advance_checked(double p_physics_step, int p_physics_ticks_per_second, double p_process_step);
// determine wall clock step since last iteration
double get_cpu_process_step();
@@ -96,7 +96,7 @@ public:
void set_fixed_fps(int p_fixed_fps);
// advance one frame, return timesteps to take
- MainFrameTime advance(double p_physics_step, int p_physics_fps);
+ MainFrameTime advance(double p_physics_step, int p_physics_ticks_per_second);
};
#endif // MAIN_TIMER_SYNC_H
diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp
index d54b1a47df..3ed3f5449e 100644
--- a/modules/gdnative/text/text_server_gdnative.cpp
+++ b/modules/gdnative/text/text_server_gdnative.cpp
@@ -498,9 +498,9 @@ bool TextServerGDNative::shaped_text_update_justification_ops(RID p_shaped) {
return interface->shaped_text_update_justification_ops(data, (godot_rid *)&p_shaped);
}
-void TextServerGDNative::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) {
+void TextServerGDNative::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_trim_flags) {
ERR_FAIL_COND(interface == nullptr);
- interface->shaped_text_overrun_trim_to_width(data, (godot_rid *)&p_shaped_line, p_width, p_clip_flags);
+ interface->shaped_text_overrun_trim_to_width(data, (godot_rid *)&p_shaped_line, p_width, p_trim_flags);
};
bool TextServerGDNative::shaped_text_is_ready(RID p_shaped) const {
diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h
index a2eb944499..e1b36f4264 100644
--- a/modules/gdnative/text/text_server_gdnative.h
+++ b/modules/gdnative/text/text_server_gdnative.h
@@ -167,7 +167,7 @@ public:
virtual bool shaped_text_update_breaks(RID p_shaped) override;
virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override;
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_trim_flags) override;
virtual bool shaped_text_is_ready(RID p_shaped) const override;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 66816f32d1..9ecb0de5b8 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -977,6 +977,7 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
p_shaped->sort_valid = false;
p_shaped->line_breaks_valid = false;
p_shaped->justification_ops_valid = false;
+ p_shaped->text_trimmed = false;
p_shaped->ascent = 0.f;
p_shaped->descent = 0.f;
p_shaped->width = 0.f;
@@ -984,6 +985,7 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
p_shaped->uthk = 0.f;
p_shaped->glyphs.clear();
p_shaped->glyphs_logical.clear();
+ p_shaped->overrun_trim_data = TrimData();
p_shaped->utf16 = Char16String();
if (p_shaped->script_iter != nullptr) {
memdelete(p_shaped->script_iter);
@@ -1375,7 +1377,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
ERR_FAIL_COND_V_MSG((start < 0 || end - start > new_sd->utf16.length()), RID(), "Invalid BiDi override range.");
- //Create temporary line bidi & shape
+ // Create temporary line bidi & shape.
UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), RID(), u_errorName(err));
ubidi_setLine(sd->bidi_iter[ov], start, end, bidi_iter, &err);
@@ -1541,6 +1543,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
const_cast<TextServerAdvanced *>(this)->shaped_text_update_justification_ops(p_shaped);
}
+ sd->fit_width_minimum_reached = false;
int start_pos = 0;
int end_pos = sd->glyphs.size() - 1;
@@ -1569,14 +1572,26 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
}
+ float justification_width;
+ if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
+ if (sd->overrun_trim_data.trim_pos >= 0) {
+ start_pos = sd->overrun_trim_data.trim_pos;
+ justification_width = sd->width_trimmed;
+ } else {
+ return sd->width;
+ }
+ } else {
+ justification_width = sd->width;
+ }
+
if ((p_jst_flags & JUSTIFICATION_TRIM_EDGE_SPACES) == JUSTIFICATION_TRIM_EDGE_SPACES) {
while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
- sd->width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
+ justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
sd->glyphs.write[start_pos].advance = 0;
start_pos += sd->glyphs[start_pos].count;
}
while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {
- sd->width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
+ justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
sd->glyphs.write[end_pos].advance = 0;
end_pos -= sd->glyphs[end_pos].count;
}
@@ -1597,7 +1612,7 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
}
if ((elongation_count > 0) && ((p_jst_flags & JUSTIFICATION_KASHIDA) == JUSTIFICATION_KASHIDA)) {
- float delta_width_per_kashida = (p_width - sd->width) / elongation_count;
+ float delta_width_per_kashida = (p_width - justification_width) / elongation_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
@@ -1605,34 +1620,50 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
int count = delta_width_per_kashida / gl.advance;
int prev_count = gl.repeat;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
- gl.repeat = count;
- } else {
- gl.repeat = count + 1;
+ gl.repeat = MAX(count, 0);
}
- sd->width += (gl.repeat - prev_count) * gl.advance;
+ justification_width += (gl.repeat - prev_count) * gl.advance;
}
}
}
}
-
+ float adv_remain = 0;
if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
- float delta_width_per_space = (p_width - sd->width) / space_count;
+ float delta_width_per_space = (p_width - justification_width) / space_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
float old_adv = gl.advance;
+ float new_advance;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
- gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.f));
+ new_advance = MAX(gl.advance + delta_width_per_space, 0.f);
} else {
- gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size));
+ new_advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size);
+ }
+ gl.advance = new_advance;
+ adv_remain += (new_advance - gl.advance);
+ if (adv_remain >= 1.0) {
+ gl.advance++;
+ adv_remain -= 1.0;
+ } else if (adv_remain <= -1.0) {
+ gl.advance = MAX(gl.advance - 1, 0);
+ adv_remain -= 1.0;
}
- sd->width += (gl.advance - old_adv);
+ justification_width += (gl.advance - old_adv);
}
}
}
}
+ if (Math::floor(p_width) < Math::floor(justification_width)) {
+ sd->fit_width_minimum_reached = true;
+ }
+
+ if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) != JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
+ sd->width = justification_width;
+ }
+
return sd->width;
}
@@ -1685,7 +1716,7 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float
return 0.f;
}
-void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) {
+void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_trim_flags) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
@@ -1693,13 +1724,22 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
shaped_text_shape(p_shaped_line);
}
- bool add_ellipsis = (p_clip_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
- bool cut_per_word = (p_clip_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
- bool enforce_ellipsis = (p_clip_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ sd->overrun_trim_data.ellipsis_glyph_buf.clear();
+
+ bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
+ bool cut_per_word = (p_trim_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
+ bool enforce_ellipsis = (p_trim_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ bool justification_aware = (p_trim_flags & OVERRUN_JUSTIFICATION_AWARE) == OVERRUN_JUSTIFICATION_AWARE;
Glyph *sd_glyphs = sd->glyphs.ptrw();
- if ((p_clip_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ sd->overrun_trim_data.trim_pos = -1;
+ sd->overrun_trim_data.ellipsis_pos = -1;
+ return;
+ }
+
+ if (justification_aware && !sd->fit_width_minimum_reached) {
return;
}
@@ -1711,9 +1751,9 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
uint32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' ');
Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, whitespace_gl_idx, last_gl_font_size);
- int ellipsis_advance = 0;
+ int ellipsis_width = 0;
if (add_ellipsis) {
- ellipsis_advance = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0);
+ ellipsis_width = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0);
}
int ell_min_characters = 6;
@@ -1733,12 +1773,12 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
if (!is_rtl) {
- width -= sd_glyphs[i].advance;
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
}
if (sd_glyphs[i].count > 0) {
bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
- if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_advance : 0) <= p_width) {
+ if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
if (cut_per_word && above_min_char_treshold) {
if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
last_valid_cut = i;
@@ -1751,7 +1791,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
if (found) {
trim_pos = last_valid_cut;
- if (above_min_char_treshold && width - ellipsis_advance <= p_width) {
+ if (add_ellipsis && (above_min_char_treshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
ellipsis_pos = trim_pos;
}
break;
@@ -1759,18 +1799,21 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
}
}
if (is_rtl) {
- width -= sd_glyphs[i].advance;
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
}
}
+ sd->overrun_trim_data.trim_pos = trim_pos;
+ sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;
+ if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) {
+ sd->overrun_trim_data.ellipsis_pos = 0;
+ }
+
if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) {
- int added_glyphs = 0;
if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
// Insert an additional space when cutting word bound for aesthetics.
if (cut_per_word && (ellipsis_pos > 0)) {
TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
gl.count = 1;
gl.advance = whitespace_adv.x;
gl.index = whitespace_gl_idx;
@@ -1778,68 +1821,33 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
gl.font_size = last_gl_font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? (-added_glyphs - 1) : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
// Add ellipsis dots.
- for (int d = 0; d < 3; d++) {
- TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
- gl.count = 1;
- gl.advance = dot_adv.x;
- gl.index = dot_gl_idx;
- gl.font_rid = last_gl_font_rid;
- gl.font_size = last_gl_font_size;
- gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
-
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? (-added_glyphs - 1) : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
- }
- }
-
- // Cut the remaining glyphs off.
- if (!is_rtl) {
- sd->glyphs.resize(trim_pos + added_glyphs);
- } else {
- if (trim_pos - added_glyphs >= 0) {
- sd->glyphs = sd->glyphs.subarray(trim_pos - added_glyphs, sd->glyphs.size() - 1);
- }
+ TextServer::Glyph gl;
+ gl.count = 1;
+ gl.repeat = 3;
+ gl.advance = dot_adv.x;
+ gl.index = dot_gl_idx;
+ gl.font_rid = last_gl_font_rid;
+ gl.font_size = last_gl_font_size;
+ gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
+
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
- // Update to correct width.
- sd->width = width + ((ellipsis_pos != -1) ? ellipsis_advance : 0);
+ sd->text_trimmed = true;
+ sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);
}
}
+TextServer::TrimData TextServerAdvanced::shaped_text_get_trim_data(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataAdvanced invalid.");
+ return sd->overrun_trim_data;
+}
+
bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
@@ -1866,7 +1874,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
int r_end = sd->spans[i].end;
UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err);
if (U_FAILURE(err)) {
- //No data loaded - use fallback.
+ // No data loaded - use fallback.
for (int j = r_start; j < r_end; j++) {
char32_t c = sd->text[j - sd->start];
if (is_whitespace(c)) {
@@ -1930,7 +1938,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
gl.font_rid = sd_glyphs[i].font_rid;
gl.font_size = sd_glyphs[i].font_size;
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd_glyphs[i].count, gl); // insert after
+ sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after.
// Update write pointer and size.
sd_size = sd->glyphs.size();
@@ -2050,7 +2058,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
UErrorCode err = U_ZERO_ERROR;
UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err);
if (U_FAILURE(err)) {
- // No data - use fallback
+ // No data - use fallback.
int limit = 0;
for (int i = 0; i < sd->text.length(); i++) {
if (is_whitespace(data[i])) {
@@ -2123,7 +2131,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
gl.font_rid = sd->glyphs[i].font_rid;
gl.font_size = sd->glyphs[i].font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd->glyphs[i].count, gl); // insert after
+ sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after.
i += sd->glyphs[i].count;
continue;
}
@@ -2189,7 +2197,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
int fs = p_sd->spans[p_span].font_size;
if (fd == nullptr) {
- // Add fallback glyphs
+ // Add fallback glyphs.
for (int i = p_start; i < p_end; i++) {
if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
TextServer::Glyph gl;
@@ -2332,7 +2340,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
}
- //Fallback.
+ // Fallback.
int failed_subrun_start = p_end + 1;
int failed_subrun_end = p_start;
@@ -2677,9 +2685,9 @@ Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(sd->width, sd->ascent + sd->descent);
+ return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent);
} else {
- return Size2(sd->ascent + sd->descent, sd->width);
+ return Size2(sd->ascent + sd->descent, (sd->text_trimmed ? sd->width_trimmed : sd->width));
}
}
@@ -2710,7 +2718,7 @@ float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
- return sd->width;
+ return (sd->text_trimmed ? sd->width_trimmed : sd->width);
}
float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const {
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index c54686c114..d19ba41a1a 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -229,7 +229,8 @@ public:
virtual bool shaped_text_update_breaks(RID p_shaped) override;
virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override;
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_trim_flags) override;
+ virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override;
virtual bool shaped_text_is_ready(RID p_shaped) const override;
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index b60bf8e8d3..110194c373 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -570,7 +570,7 @@ void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::O
}
void TextServerFallback::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
- //No BiDi support, ignore.
+ // No BiDi support, ignore.
}
TextServer::Orientation TextServerFallback::shaped_text_get_orientation(RID p_shaped) const {
@@ -1173,7 +1173,7 @@ bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) {
return true;
}
-void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_clip_flags) {
+void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint8_t p_trim_flags) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
@@ -1181,13 +1181,22 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
shaped_text_shape(p_shaped_line);
}
- bool add_ellipsis = (p_clip_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
- bool cut_per_word = (p_clip_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
- bool enforce_ellipsis = (p_clip_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ sd->overrun_trim_data.ellipsis_glyph_buf.clear();
+
+ bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
+ bool cut_per_word = (p_trim_flags & OVERRUN_TRIM_WORD_ONLY) == OVERRUN_TRIM_WORD_ONLY;
+ bool enforce_ellipsis = (p_trim_flags & OVERRUN_ENFORCE_ELLIPSIS) == OVERRUN_ENFORCE_ELLIPSIS;
+ bool justification_aware = (p_trim_flags & OVERRUN_JUSTIFICATION_AWARE) == OVERRUN_JUSTIFICATION_AWARE;
Glyph *sd_glyphs = sd->glyphs.ptrw();
- if ((p_clip_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIMMING || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ sd->overrun_trim_data.trim_pos = -1;
+ sd->overrun_trim_data.ellipsis_pos = -1;
+ return;
+ }
+
+ if (justification_aware && !sd->fit_width_minimum_reached) {
return;
}
@@ -1199,34 +1208,27 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
uint32_t whitespace_gl_idx = font_get_glyph_index(last_gl_font_rid, ' ');
Vector2 whitespace_adv = font_get_glyph_advance(last_gl_font_rid, whitespace_gl_idx, last_gl_font_size);
- int ellipsis_advance = 0;
+ int ellipsis_width = 0;
if (add_ellipsis) {
- ellipsis_advance = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0);
+ ellipsis_width = 3 * dot_adv.x + font_get_spacing_glyph(last_gl_font_rid) + (cut_per_word ? whitespace_adv.x : 0);
}
int ell_min_characters = 6;
float width = sd->width;
- bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL);
-
- int trim_pos = (is_rtl) ? sd_size : 0;
+ int trim_pos = 0;
int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;
int last_valid_cut = 0;
bool found = false;
- int glyphs_from = (is_rtl) ? 0 : sd_size - 1;
- int glyphs_to = (is_rtl) ? sd_size - 1 : -1;
- int glyphs_delta = (is_rtl) ? +1 : -1;
+ for (int i = sd_size - 1; i != -1; i--) {
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
- for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
- if (!is_rtl) {
- width -= sd_glyphs[i].advance;
- }
if (sd_glyphs[i].count > 0) {
- bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
+ bool above_min_char_treshold = (i >= ell_min_characters);
- if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_advance : 0) <= p_width) {
+ if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
if (cut_per_word && above_min_char_treshold) {
if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
last_valid_cut = i;
@@ -1239,95 +1241,60 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl
if (found) {
trim_pos = last_valid_cut;
- if (above_min_char_treshold && width - ellipsis_advance <= p_width) {
+ if (add_ellipsis && (above_min_char_treshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
ellipsis_pos = trim_pos;
}
break;
}
}
}
- if (is_rtl) {
- width -= sd_glyphs[i].advance;
- }
+ }
+
+ sd->overrun_trim_data.trim_pos = trim_pos;
+ sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;
+ if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) {
+ sd->overrun_trim_data.ellipsis_pos = 0;
}
if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) {
- int added_glyphs = 0;
if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
// Insert an additional space when cutting word bound for aesthetics.
if (cut_per_word && (ellipsis_pos > 0)) {
TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
gl.count = 1;
gl.advance = whitespace_adv.x;
gl.index = whitespace_gl_idx;
gl.font_rid = last_gl_font_rid;
gl.font_size = last_gl_font_size;
- gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
+ gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? -added_glyphs : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
// Add ellipsis dots.
- for (int d = 0; d < 3; d++) {
- TextServer::Glyph gl;
- gl.start = sd_glyphs[ellipsis_pos].start;
- gl.end = sd_glyphs[ellipsis_pos].end;
- gl.count = 1;
- gl.advance = dot_adv.x;
- gl.index = dot_gl_idx;
- gl.font_rid = last_gl_font_rid;
- gl.font_size = last_gl_font_size;
- gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
-
- // Optimized glyph insertion by replacing a glyph whenever possible.
- int glyph_idx = trim_pos + ((is_rtl) ? -added_glyphs : added_glyphs);
- if (is_rtl) {
- if (glyph_idx < 0) {
- sd->glyphs.insert(0, gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- } else {
- if (glyph_idx > (sd_size - 1)) {
- sd->glyphs.append(gl);
- } else {
- sd->glyphs.set(glyph_idx, gl);
- }
- }
- added_glyphs++;
- }
- }
-
- // Cut the remaining glyphs off.
- if (!is_rtl) {
- sd->glyphs.resize(trim_pos + added_glyphs);
- } else {
- for (int ridx = 0; ridx <= trim_pos - added_glyphs; ridx++) {
- sd->glyphs.remove(0);
- }
+ TextServer::Glyph gl;
+ gl.count = 1;
+ gl.repeat = 3;
+ gl.advance = dot_adv.x;
+ gl.index = dot_gl_idx;
+ gl.font_rid = last_gl_font_rid;
+ gl.font_size = last_gl_font_size;
+ gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL;
+
+ sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
- // Update to correct width.
- sd->width = width + ((ellipsis_pos != -1) ? ellipsis_advance : 0);
+ sd->text_trimmed = true;
+ sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);
}
}
+TextServer::TrimData TextServerFallback::shaped_text_get_trim_data(RID p_shaped) const {
+ _THREAD_SAFE_METHOD_
+ ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataAdvanced invalid.");
+ return sd->overrun_trim_data;
+}
+
bool TextServerFallback::shaped_text_shape(RID p_shaped) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index e3bbde76d4..d4cab2409a 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -178,7 +178,8 @@ public:
virtual bool shaped_text_update_breaks(RID p_shaped) override;
virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) override;
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_trim_flags) override;
+ virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override;
virtual bool shaped_text_is_ready(RID p_shaped) const override;
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 2d3feb30a1..fa19d5c2cf 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -39,8 +39,8 @@
#include "scene/scene_string_names.h"
void PhysicsBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.08));
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.08));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08));
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
@@ -59,10 +59,10 @@ PhysicsBody2D::~PhysicsBody2D() {
}
}
-Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) {
+Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin) {
PhysicsServer2D::MotionResult result;
- if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) {
+ if (move_and_collide(p_motion, result, p_margin, p_test_only)) {
if (motion_cache.is_null()) {
motion_cache.instantiate();
motion_cache->owner = this;
@@ -75,12 +75,12 @@ Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_i
return Ref<KinematicCollision2D>();
}
-bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) {
+bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) {
if (is_only_update_transform_changes_enabled()) {
ERR_PRINT("Move functions do not work together with 'sync to physics' option. Please read the documentation.");
}
Transform2D gt = get_global_transform();
- bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes, p_exclude);
+ bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_exclude);
// Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery,
@@ -128,7 +128,7 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_in
return colliding;
}
-bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
+bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer2D::MotionResult *r = nullptr;
@@ -137,7 +137,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion
r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result);
}
- return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes);
+ return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r);
}
TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
@@ -1080,7 +1080,7 @@ void CharacterBody2D::move_and_slide() {
PhysicsServer2D::MotionResult floor_result;
Set<RID> exclude;
exclude.insert(platform_rid);
- if (move_and_collide(current_platform_velocity * delta, infinite_inertia, floor_result, true, false, false, false, exclude)) {
+ if (move_and_collide(current_platform_velocity * delta, floor_result, margin, false, false, exclude)) {
motion_results.push_back(floor_result);
_set_collision_direction(floor_result);
}
@@ -1113,123 +1113,113 @@ void CharacterBody2D::move_and_slide() {
Vector2 prev_position = get_global_transform().elements[2];
- for (int i = 0; i < 2; ++i) {
- bool collided;
- if (i == 0) { // Collide.
- collided = move_and_collide(motion, infinite_inertia, result, margin, true, false, !sliding_enabled);
- } else { // Separate raycasts (if any).
- collided = separate_raycast_shapes(result);
- if (collided) {
- result.remainder = motion; // Keep.
- result.motion = Vector2();
+ bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled);
+
+ if (collided) {
+ found_collision = true;
+ motion_results.push_back(result);
+ _set_collision_direction(result);
+
+ if (on_floor && stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
+ Transform2D gt = get_global_transform();
+ if (result.motion.length() > margin) {
+ gt.elements[2] -= result.motion.slide(up_direction);
+ } else {
+ gt.elements[2] -= result.motion;
}
+ set_global_transform(gt);
+ linear_velocity = Vector2();
+ motion = Vector2();
+ break;
}
- if (collided) {
- found_collision = true;
- motion_results.push_back(result);
- _set_collision_direction(result);
+ if (result.remainder.is_equal_approx(Vector2())) {
+ motion = Vector2();
+ break;
+ }
- if (on_floor && stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
- Transform2D gt = get_global_transform();
- if (result.motion.length() > margin) {
- gt.elements[2] -= result.motion.slide(up_direction);
- } else {
+ // Move on floor only checks.
+ if (move_on_floor_only && on_wall && motion_slide_up.dot(result.collision_normal) <= 0) {
+ // Avoid to move forward on a wall if move_on_floor_only is true.
+ if (was_on_floor && !is_on_floor_only() && !vel_dir_facing_up) {
+ // If the movement is large the body can be prevented from reaching the walls.
+ if (result.motion.length() <= margin) {
+ // Cancels the motion.
+ Transform2D gt = get_global_transform();
gt.elements[2] -= result.motion;
+ set_global_transform(gt);
}
- set_global_transform(gt);
+ on_floor = true;
+ platform_rid = prev_platform_rid;
+ platform_layer = prev_platform_layer;
+
+ platform_velocity = prev_platform_velocity;
+ floor_normal = prev_floor_normal;
linear_velocity = Vector2();
motion = Vector2();
break;
}
-
- if (result.remainder.is_equal_approx(Vector2())) {
- motion = Vector2();
- break;
+ // Prevents the body from being able to climb a slope when it moves forward against the wall.
+ else if (!is_on_floor_only()) {
+ motion = up_direction * up_direction.dot(result.remainder);
+ motion = motion.slide(result.collision_normal);
+ } else {
+ motion = result.remainder;
}
-
- // Move on floor only checks.
- if (move_on_floor_only && on_wall && motion_slide_up.dot(result.collision_normal) <= 0) {
- // Avoid to move forward on a wall if move_on_floor_only is true.
- if (was_on_floor && !is_on_floor_only() && !vel_dir_facing_up) {
- // If the movement is large the body can be prevented from reaching the walls.
- if (result.motion.length() <= margin) {
- // Cancels the motion.
- Transform2D gt = get_global_transform();
- gt.elements[2] -= result.motion;
- set_global_transform(gt);
- }
- on_floor = true;
- platform_rid = prev_platform_rid;
- platform_layer = prev_platform_layer;
-
- platform_velocity = prev_platform_velocity;
- floor_normal = prev_floor_normal;
- linear_velocity = Vector2();
- motion = Vector2();
- break;
- }
- // Prevents the body from being able to climb a slope when it moves forward against the wall.
- else if (!is_on_floor_only()) {
- motion = up_direction * up_direction.dot(result.remainder);
- motion = motion.slide(result.collision_normal);
- } else {
- motion = result.remainder;
- }
+ }
+ // Constant Speed when the slope is upward.
+ else if (constant_speed_on_floor && is_on_floor_only() && can_apply_constant_speed && was_on_floor && motion.dot(result.collision_normal) < 0) {
+ can_apply_constant_speed = false;
+ Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized();
+ if (!motion_slide_norm.is_equal_approx(Vector2())) {
+ motion = motion_slide_norm * (motion_slide_up.length() - result.motion.slide(up_direction).length() - last_travel.slide(up_direction).length());
}
- // Constant Speed when the slope is upward.
- else if (constant_speed_on_floor && is_on_floor_only() && can_apply_constant_speed && was_on_floor && motion.dot(result.collision_normal) < 0) {
- can_apply_constant_speed = false;
- Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized();
- if (!motion_slide_norm.is_equal_approx(Vector2())) {
- motion = motion_slide_norm * (motion_slide_up.length() - result.motion.slide(up_direction).length() - last_travel.slide(up_direction).length());
- }
+ }
+ // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling.
+ else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up)) {
+ Vector2 slide_motion = result.remainder.slide(result.collision_normal);
+ if (slide_motion.dot(linear_velocity) > 0.0) {
+ motion = slide_motion;
+ } else {
+ motion = Vector2();
}
- // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling.
- else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up)) {
- Vector2 slide_motion = result.remainder.slide(result.collision_normal);
- if (slide_motion.dot(linear_velocity) > 0.0) {
- motion = slide_motion;
+ if (slide_on_ceiling && on_ceiling) {
+ // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall.
+ if (vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(result.collision_normal);
} else {
- motion = Vector2();
- }
- if (slide_on_ceiling && on_ceiling) {
- // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall.
- if (vel_dir_facing_up) {
- linear_velocity = linear_velocity.slide(result.collision_normal);
- } else {
- // Avoid acceleration in slope when falling.
- linear_velocity = up_direction * up_direction.dot(linear_velocity);
- }
+ // Avoid acceleration in slope when falling.
+ linear_velocity = up_direction * up_direction.dot(linear_velocity);
}
}
- // No sliding on first attempt to keep floor motion stable when possible.
- else {
- motion = result.remainder;
- if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) {
- linear_velocity = linear_velocity.slide(up_direction);
- motion = motion.slide(up_direction);
- }
+ }
+ // No sliding on first attempt to keep floor motion stable when possible.
+ else {
+ motion = result.remainder;
+ if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(up_direction);
+ motion = motion.slide(up_direction);
}
-
- last_travel = result.motion;
}
- // When you move forward in a downward slope you don’t collide because you will be in the air.
- // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied.
- else if (i == 0 && constant_speed_on_floor && first_slide && _on_floor_if_snapped(was_on_floor, vel_dir_facing_up)) {
- can_apply_constant_speed = false;
- sliding_enabled = true;
- Transform2D gt = get_global_transform();
- gt.elements[2] = prev_position;
- set_global_transform(gt);
- Vector2 motion_slide_norm = motion.slide(prev_floor_normal).normalized();
- if (!motion_slide_norm.is_equal_approx(Vector2())) {
- motion = motion_slide_norm * (motion_slide_up.length());
- found_collision = true;
- }
+ last_travel = result.motion;
+ }
+ // When you move forward in a downward slope you don’t collide because you will be in the air.
+ // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied.
+ else if (constant_speed_on_floor && first_slide && _on_floor_if_snapped(was_on_floor, vel_dir_facing_up)) {
+ can_apply_constant_speed = false;
+ sliding_enabled = true;
+ Transform2D gt = get_global_transform();
+ gt.elements[2] = prev_position;
+ set_global_transform(gt);
+
+ Vector2 motion_slide_norm = motion.slide(prev_floor_normal).normalized();
+ if (!motion_slide_norm.is_equal_approx(Vector2())) {
+ motion = motion_slide_norm * (motion_slide_up.length());
+ found_collision = true;
}
}
+
can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled;
sliding_enabled = true;
first_slide = false;
@@ -1259,7 +1249,7 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
Transform2D gt = get_global_transform();
PhysicsServer2D::MotionResult result;
- if (move_and_collide(up_direction * -floor_snap_length, infinite_inertia, result, margin, false, true, false)) {
+ if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false)) {
bool apply = true;
float collision_angle = Math::acos(result.collision_normal.dot(up_direction));
if (collision_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
@@ -1294,7 +1284,7 @@ bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facin
}
PhysicsServer2D::MotionResult result;
- if (move_and_collide(up_direction * -floor_snap_length, infinite_inertia, result, margin, false, true, false)) {
+ if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false)) {
if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
return true;
}
@@ -1331,42 +1321,6 @@ void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_
}
}
-bool CharacterBody2D::separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result) {
- PhysicsServer2D::SeparationResult sep_res[8]; //max 8 rays
-
- Transform2D gt = get_global_transform();
-
- Vector2 recover;
- int hits = PhysicsServer2D::get_singleton()->body_test_ray_separation(get_rid(), gt, infinite_inertia, recover, sep_res, 8, margin);
- int deepest = -1;
- real_t deepest_depth;
- for (int i = 0; i < hits; i++) {
- if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
- deepest = i;
- deepest_depth = sep_res[i].collision_depth;
- }
- }
-
- gt.elements[2] += recover;
- set_global_transform(gt);
-
- if (deepest != -1) {
- r_result.collider_id = sep_res[deepest].collider_id;
- r_result.collider_metadata = sep_res[deepest].collider_metadata;
- r_result.collider_shape = sep_res[deepest].collider_shape;
- r_result.collider_velocity = sep_res[deepest].collider_velocity;
- r_result.collision_point = sep_res[deepest].collision_point;
- r_result.collision_normal = sep_res[deepest].collision_normal;
- r_result.collision_local_shape = sep_res[deepest].collision_local_shape;
- r_result.motion = recover;
- r_result.remainder = Vector2();
-
- return true;
- } else {
- return false;
- }
-}
-
const Vector2 &CharacterBody2D::get_linear_velocity() const {
return linear_velocity;
}
@@ -1447,16 +1401,10 @@ void CharacterBody2D::set_stop_on_slope_enabled(bool p_enabled) {
stop_on_slope = p_enabled;
}
-bool CharacterBody2D::is_infinite_inertia_enabled() const {
- return infinite_inertia;
-}
-void CharacterBody2D::set_infinite_inertia_enabled(bool p_enabled) {
- infinite_inertia = p_enabled;
-}
-
bool CharacterBody2D::is_constant_speed_on_floor_enabled() const {
return constant_speed_on_floor;
}
+
void CharacterBody2D::set_constant_speed_on_floor_enabled(bool p_enabled) {
constant_speed_on_floor = p_enabled;
}
@@ -1464,6 +1412,7 @@ void CharacterBody2D::set_constant_speed_on_floor_enabled(bool p_enabled) {
bool CharacterBody2D::is_move_on_floor_only_enabled() const {
return move_on_floor_only;
}
+
void CharacterBody2D::set_move_on_floor_only_enabled(bool p_enabled) {
move_on_floor_only = p_enabled;
}
@@ -1471,6 +1420,7 @@ void CharacterBody2D::set_move_on_floor_only_enabled(bool p_enabled) {
bool CharacterBody2D::is_slide_on_ceiling_enabled() const {
return slide_on_ceiling;
}
+
void CharacterBody2D::set_slide_on_ceiling_enabled(bool p_enabled) {
slide_on_ceiling = p_enabled;
}
@@ -1541,7 +1491,6 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin);
ClassDB::bind_method(D_METHOD("is_stop_on_slope_enabled"), &CharacterBody2D::is_stop_on_slope_enabled);
ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_stop_on_slope_enabled);
- ClassDB::bind_method(D_METHOD("is_infinite_inertia_enabled"), &CharacterBody2D::is_infinite_inertia_enabled);
ClassDB::bind_method(D_METHOD("set_constant_speed_on_floor_enabled", "enabled"), &CharacterBody2D::set_constant_speed_on_floor_enabled);
ClassDB::bind_method(D_METHOD("is_constant_speed_on_floor_enabled"), &CharacterBody2D::is_constant_speed_on_floor_enabled);
ClassDB::bind_method(D_METHOD("set_move_on_floor_only_enabled", "enabled"), &CharacterBody2D::set_move_on_floor_only_enabled);
@@ -1552,7 +1501,6 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_body_layers", "exclude_layer"), &CharacterBody2D::set_exclude_body_layers);
ClassDB::bind_method(D_METHOD("get_exclude_body_layers"), &CharacterBody2D::get_exclude_body_layers);
- ClassDB::bind_method(D_METHOD("set_infinite_inertia_enabled", "enabled"), &CharacterBody2D::set_infinite_inertia_enabled);
ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides);
ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides);
ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody2D::get_floor_max_angle);
@@ -1575,7 +1523,6 @@ void CharacterBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "constant_speed_on_floor"), "set_constant_speed_on_floor_enabled", "is_constant_speed_on_floor_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "move_on_floor_only"), "set_move_on_floor_only_enabled", "is_move_on_floor_only_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled");
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 00948b4344..3d894416f0 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -47,11 +47,11 @@ protected:
Ref<KinematicCollision2D> motion_cache;
- Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.08);
+ Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08);
public:
- bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true, const Set<RID> &p_exclude = Set<RID>());
- bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08);
+ bool move_and_collide(const Vector2 &p_motion, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_test_only = false, bool p_cancel_sliding = true, const Set<RID> &p_exclude = Set<RID>());
+ bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08);
TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
@@ -272,7 +272,6 @@ private:
real_t margin = 0.08;
bool stop_on_slope = false;
- bool infinite_inertia = true;
bool constant_speed_on_floor = false;
bool move_on_floor_only = true;
bool slide_on_ceiling = true;
@@ -294,17 +293,12 @@ private:
Vector<PhysicsServer2D::MotionResult> motion_results;
Vector<Ref<KinematicCollision2D>> slide_colliders;
- bool separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result);
-
void set_safe_margin(real_t p_margin);
real_t get_safe_margin() const;
bool is_stop_on_slope_enabled() const;
void set_stop_on_slope_enabled(bool p_enabled);
- bool is_infinite_inertia_enabled() const;
- void set_infinite_inertia_enabled(bool p_enabled);
-
bool is_constant_speed_on_floor_enabled() const;
void set_constant_speed_on_floor_enabled(bool p_enabled);
@@ -317,9 +311,6 @@ private:
int get_max_slides() const;
void set_max_slides(int p_max_slides);
- real_t get_move_max_angle() const;
- void set_move_max_angle(real_t p_radians);
-
real_t get_floor_max_angle() const;
void set_floor_max_angle(real_t p_radians);
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 9643d33c86..36d4c8f4f0 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -33,17 +33,10 @@
#include "core/math/quick_hull.h"
#include "mesh_instance_3d.h"
#include "physics_body_3d.h"
-#include "scene/resources/box_shape_3d.h"
-#include "scene/resources/capsule_shape_3d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
-#include "scene/resources/ray_shape_3d.h"
-#include "scene/resources/sphere_shape_3d.h"
-#include "scene/resources/world_margin_shape_3d.h"
#include "servers/rendering_server.h"
-//TODO: Implement CylinderShape and HeightMapShape?
-
void CollisionShape3D::make_convex_from_siblings() {
Node *p = get_parent();
if (!p) {
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 53ec07f1ce..331a460dee 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -44,8 +44,8 @@
#endif
void PhysicsBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.001));
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody3D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.001));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001));
ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock);
ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock);
@@ -101,9 +101,9 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) {
+Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin) {
PhysicsServer3D::MotionResult result;
- if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) {
+ if (move_and_collide(p_motion, result, p_margin, p_test_only)) {
if (motion_cache.is_null()) {
motion_cache.instantiate();
motion_cache->owner = this;
@@ -117,9 +117,9 @@ Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_i
return Ref<KinematicCollision3D>();
}
-bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) {
+bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) {
Transform3D gt = get_global_transform();
- bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes, p_exclude);
+ bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_exclude);
// Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery,
@@ -173,7 +173,7 @@ bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
return colliding;
}
-bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision3D> &r_collision, real_t p_margin) {
+bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision, real_t p_margin) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer3D::MotionResult *r = nullptr;
@@ -182,7 +182,7 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion
r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result);
}
- return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes);
+ return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r);
}
void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
@@ -1121,7 +1121,7 @@ void CharacterBody3D::move_and_slide() {
PhysicsServer3D::MotionResult floor_result;
Set<RID> exclude;
exclude.insert(on_floor_body);
- if (move_and_collide(current_floor_velocity * delta, infinite_inertia, floor_result, true, false, false, false, exclude)) {
+ if (move_and_collide(current_floor_velocity * delta, floor_result, margin, false, false, exclude)) {
motion_results.push_back(floor_result);
_set_collision_direction(floor_result);
}
@@ -1138,58 +1138,45 @@ void CharacterBody3D::move_and_slide() {
PhysicsServer3D::MotionResult result;
bool found_collision = false;
- for (int i = 0; i < 2; ++i) {
- bool collided;
- if (i == 0) { //collide
- collided = move_and_collide(motion, infinite_inertia, result, margin, true, false, !sliding_enabled);
- if (!collided) {
- motion = Vector3(); //clear because no collision happened and motion completed
- }
- } else { //separate raycasts (if any)
- collided = separate_raycast_shapes(result);
- if (collided) {
- result.remainder = motion; //keep
- result.motion = Vector3();
- }
- }
+ bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled);
+ if (!collided) {
+ motion = Vector3(); //clear because no collision happened and motion completed
+ } else {
+ found_collision = true;
- if (collided) {
- found_collision = true;
-
- motion_results.push_back(result);
- _set_collision_direction(result);
-
- if (on_floor && stop_on_slope) {
- if ((body_velocity_normal + up_direction).length() < 0.01) {
- Transform3D gt = get_global_transform();
- if (result.motion.length() > margin) {
- gt.origin -= result.motion.slide(up_direction);
- } else {
- gt.origin -= result.motion;
- }
- set_global_transform(gt);
- linear_velocity = Vector3();
- return;
+ motion_results.push_back(result);
+ _set_collision_direction(result);
+
+ if (on_floor && stop_on_slope) {
+ if ((body_velocity_normal + up_direction).length() < 0.01) {
+ Transform3D gt = get_global_transform();
+ if (result.motion.length() > margin) {
+ gt.origin -= result.motion.slide(up_direction);
+ } else {
+ gt.origin -= result.motion;
}
+ set_global_transform(gt);
+ linear_velocity = Vector3();
+ return;
}
+ }
- if (sliding_enabled || !on_floor) {
- motion = result.remainder.slide(result.collision_normal);
- linear_velocity = linear_velocity.slide(result.collision_normal);
+ if (sliding_enabled || !on_floor) {
+ motion = result.remainder.slide(result.collision_normal);
+ linear_velocity = linear_velocity.slide(result.collision_normal);
- for (int j = 0; j < 3; j++) {
- if (locked_axis & (1 << j)) {
- linear_velocity[j] = 0.0;
- }
+ for (int j = 0; j < 3; j++) {
+ if (locked_axis & (1 << j)) {
+ linear_velocity[j] = 0.0;
}
- } else {
- motion = result.remainder;
}
+ } else {
+ motion = result.remainder;
}
-
- sliding_enabled = true;
}
+ sliding_enabled = true;
+
if (!found_collision || motion == Vector3()) {
break;
}
@@ -1207,7 +1194,7 @@ void CharacterBody3D::move_and_slide() {
// Apply snap.
Transform3D gt = get_global_transform();
PhysicsServer3D::MotionResult result;
- if (move_and_collide(snap, infinite_inertia, result, margin, false, true, false)) {
+ if (move_and_collide(snap, result, margin, true, false)) {
bool apply = true;
if (up_direction != Vector3()) {
if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
@@ -1258,42 +1245,6 @@ void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResu
}
}
-bool CharacterBody3D::separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result) {
- PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays
-
- Transform3D gt = get_global_transform();
-
- Vector3 recover;
- int hits = PhysicsServer3D::get_singleton()->body_test_ray_separation(get_rid(), gt, infinite_inertia, recover, sep_res, 8, margin);
- int deepest = -1;
- real_t deepest_depth;
- for (int i = 0; i < hits; i++) {
- if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
- deepest = i;
- deepest_depth = sep_res[i].collision_depth;
- }
- }
-
- gt.origin += recover;
- set_global_transform(gt);
-
- if (deepest != -1) {
- r_result.collider_id = sep_res[deepest].collider_id;
- r_result.collider_metadata = sep_res[deepest].collider_metadata;
- r_result.collider_shape = sep_res[deepest].collider_shape;
- r_result.collider_velocity = sep_res[deepest].collider_velocity;
- r_result.collision_point = sep_res[deepest].collision_point;
- r_result.collision_normal = sep_res[deepest].collision_normal;
- r_result.collision_local_shape = sep_res[deepest].collision_local_shape;
- r_result.motion = recover;
- r_result.remainder = Vector3();
-
- return true;
- } else {
- return false;
- }
-}
-
void CharacterBody3D::set_safe_margin(real_t p_margin) {
margin = p_margin;
}
@@ -1362,13 +1313,6 @@ void CharacterBody3D::set_stop_on_slope_enabled(bool p_enabled) {
stop_on_slope = p_enabled;
}
-bool CharacterBody3D::is_infinite_inertia_enabled() const {
- return infinite_inertia;
-}
-void CharacterBody3D::set_infinite_inertia_enabled(bool p_enabled) {
- infinite_inertia = p_enabled;
-}
-
int CharacterBody3D::get_max_slides() const {
return max_slides;
}
@@ -1426,8 +1370,6 @@ void CharacterBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin);
ClassDB::bind_method(D_METHOD("is_stop_on_slope_enabled"), &CharacterBody3D::is_stop_on_slope_enabled);
ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_stop_on_slope_enabled);
- ClassDB::bind_method(D_METHOD("is_infinite_inertia_enabled"), &CharacterBody3D::is_infinite_inertia_enabled);
- ClassDB::bind_method(D_METHOD("set_infinite_inertia_enabled", "enabled"), &CharacterBody3D::set_infinite_inertia_enabled);
ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides);
ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides);
ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody3D::get_floor_max_angle);
@@ -1448,7 +1390,6 @@ void CharacterBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_RANGE, "1,8,1,or_greater"), "set_max_slides", "get_max_slides");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "snap"), "set_snap", "get_snap");
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 227e6d43b6..b076560ead 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -50,11 +50,11 @@ protected:
uint16_t locked_axis = 0;
- Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.001);
+ Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001);
public:
- bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true, const Set<RID> &p_exclude = Set<RID>());
- bool test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001);
+ bool move_and_collide(const Vector3 &p_motion, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_test_only = false, bool p_cancel_sliding = true, const Set<RID> &p_exclude = Set<RID>());
+ bool test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001);
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
@@ -279,7 +279,6 @@ private:
real_t margin = 0.001;
bool stop_on_slope = false;
- bool infinite_inertia = true;
int max_slides = 4;
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
Vector3 snap;
@@ -300,17 +299,12 @@ private:
void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result);
- bool separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result);
-
void set_safe_margin(real_t p_margin);
real_t get_safe_margin() const;
bool is_stop_on_slope_enabled() const;
void set_stop_on_slope_enabled(bool p_enabled);
- bool is_infinite_inertia_enabled() const;
- void set_infinite_inertia_enabled(bool p_enabled);
-
int get_max_slides() const;
void set_max_slides(int p_max_slides);
diff --git a/scene/3d/velocity_tracker_3d.cpp b/scene/3d/velocity_tracker_3d.cpp
index a027749eaa..8f4fecb348 100644
--- a/scene/3d/velocity_tracker_3d.cpp
+++ b/scene/3d/velocity_tracker_3d.cpp
@@ -70,7 +70,7 @@ Vector3 VelocityTracker3D::get_tracked_linear_velocity() const {
if (position_history_len) {
if (physics_step) {
uint64_t base = Engine::get_singleton()->get_physics_frames();
- base_time = double(base - position_history[0].frame) / Engine::get_singleton()->get_iterations_per_second();
+ base_time = double(base - position_history[0].frame) / Engine::get_singleton()->get_physics_ticks_per_second();
} else {
uint64_t base = Engine::get_singleton()->get_frame_ticks();
base_time = double(base - position_history[0].frame) / 1000000.0;
@@ -83,7 +83,7 @@ Vector3 VelocityTracker3D::get_tracked_linear_velocity() const {
Vector3 distance = position_history[i].position - position_history[i + 1].position;
if (physics_step) {
- delta = double(diff) / Engine::get_singleton()->get_iterations_per_second();
+ delta = double(diff) / Engine::get_singleton()->get_physics_ticks_per_second();
} else {
delta = double(diff) / 1000000.0;
}
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 1603989243..50db1fc3ce 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -95,7 +95,6 @@ void Label::_shape() {
lines_dirty = true;
}
- uint8_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
if (lines_dirty) {
for (int i = 0; i < lines_rid.size(); i++) {
TS->free(lines_rid[i]);
@@ -116,53 +115,19 @@ void Label::_shape() {
case AUTOWRAP_OFF:
break;
}
- Vector<Vector2i> lines = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
-
- for (int i = 0; i < lines.size(); i++) {
- RID line = TS->shaped_text_substr(text_rid, lines[i].x, lines[i].y - lines[i].x);
-
- switch (overrun_behavior) {
- case OVERRUN_TRIM_WORD_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
- break;
- case OVERRUN_TRIM_ELLIPSIS:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
- break;
- case OVERRUN_TRIM_WORD:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
- break;
- case OVERRUN_TRIM_CHAR:
- overrun_flags |= TextServer::OVERRUN_TRIM;
- break;
- case OVERRUN_NO_TRIMMING:
- break;
- }
-
- if (autowrap_mode == AUTOWRAP_OFF && align != ALIGN_FILL && overrun_behavior != OVERRUN_NO_TRIMMING) {
- TS->shaped_text_overrun_trim_to_width(line, width, overrun_flags);
- }
+ Vector<Vector2i> line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
+ for (int i = 0; i < line_breaks.size(); i++) {
+ RID line = TS->shaped_text_substr(text_rid, line_breaks[i].x, line_breaks[i].y - line_breaks[i].x);
lines_rid.push_back(line);
}
-
- if (autowrap_mode != AUTOWRAP_OFF && overrun_behavior != OVERRUN_NO_TRIMMING) {
- int visible_lines = get_visible_line_count();
-
- if (visible_lines < lines_rid.size() && visible_lines > 0) {
- overrun_flags |= TextServer::OVERRUN_ENFORCE_ELLIPSIS;
- TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
- }
- }
}
if (xl_text.length() == 0) {
minsize = Size2(1, get_line_height());
return;
}
+
if (autowrap_mode == AUTOWRAP_OFF) {
minsize.width = 0.0f;
for (int i = 0; i < lines_rid.size(); i++) {
@@ -173,19 +138,59 @@ void Label::_shape() {
}
if (lines_dirty) {
+ uint8_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
+ switch (overrun_behavior) {
+ case OVERRUN_TRIM_WORD_ELLIPSIS:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ break;
+ case OVERRUN_TRIM_ELLIPSIS:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ break;
+ case OVERRUN_TRIM_WORD:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ break;
+ case OVERRUN_TRIM_CHAR:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ break;
+ case OVERRUN_NO_TRIMMING:
+ break;
+ }
+
// Fill after min_size calculation.
- if (align == ALIGN_FILL) {
+
+ if (autowrap_mode != AUTOWRAP_OFF) {
+ int visible_lines = get_visible_line_count();
+ bool lines_hidden = visible_lines > 0 && visible_lines < lines_rid.size();
+ if (lines_hidden) {
+ overrun_flags |= TextServer::OVERRUN_ENFORCE_ELLIPSIS;
+ }
+ if (align == ALIGN_FILL) {
+ for (int i = 0; i < lines_rid.size(); i++) {
+ if (i < visible_lines - 1 || lines_rid.size() == 1) {
+ TS->shaped_text_fit_to_width(lines_rid[i], width);
+ } else if (i == (visible_lines - 1)) {
+ TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
+ }
+ }
+
+ } else if (lines_hidden) {
+ TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
+ }
+
+ } else {
+ // Autowrap disabled.
for (int i = 0; i < lines_rid.size(); i++) {
- if (overrun_behavior != OVERRUN_NO_TRIMMING && autowrap_mode == AUTOWRAP_OFF) {
- float line_unaltered_width = TS->shaped_text_get_width(lines_rid[i]);
+ if (align == ALIGN_FILL) {
TS->shaped_text_fit_to_width(lines_rid[i], width);
- float new_line_width = TS->shaped_text_get_width(lines_rid[i]);
- // Begin trimming when there is no space between words available anymore.
- if (new_line_width < line_unaltered_width) {
- TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
- }
+ overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
+ TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
+ TS->shaped_text_fit_to_width(lines_rid[i], width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
} else {
- TS->shaped_text_fit_to_width(lines_rid[i], width);
+ TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
}
}
}
@@ -219,11 +224,30 @@ void Label::_update_visible() {
}
}
+inline void draw_glyph(const TextServer::Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Color &p_font_shadow_color, const Color &p_font_outline_color, const int &p_shadow_outline_size, const int &p_outline_size, const Vector2 &p_ofs, const Vector2 &shadow_ofs) {
+ if (p_gl.font_rid != RID()) {
+ if (p_font_shadow_color.a > 0) {
+ TS->font_draw_glyph(p_gl.font_rid, p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + shadow_ofs, p_gl.index, p_font_shadow_color);
+ if (p_shadow_outline_size > 0) {
+ TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_shadow_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + Vector2(-shadow_ofs.x, shadow_ofs.y), p_gl.index, p_font_shadow_color);
+ TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_shadow_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + Vector2(shadow_ofs.x, -shadow_ofs.y), p_gl.index, p_font_shadow_color);
+ TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_shadow_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + Vector2(-shadow_ofs.x, -shadow_ofs.y), p_gl.index, p_font_shadow_color);
+ }
+ }
+ if (p_font_outline_color.a != 0.0 && p_outline_size > 0) {
+ TS->font_draw_glyph_outline(p_gl.font_rid, p_canvas, p_gl.font_size, p_outline_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_outline_color);
+ }
+ TS->font_draw_glyph(p_gl.font_rid, p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_color);
+ } else {
+ TS->draw_hex_code_box(p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_color);
+ }
+}
+
void Label::_notification(int p_what) {
if (p_what == NOTIFICATION_TRANSLATION_CHANGED) {
String new_text = atr(text);
if (new_text == xl_text) {
- return; //nothing new
+ return; // Nothing new.
}
xl_text = new_text;
dirty = true;
@@ -253,7 +277,7 @@ void Label::_notification(int p_what) {
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
int shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
- bool rtl = is_layout_rtl();
+ bool rtl = TS->shaped_text_get_direction(text_rid);
style->draw(ci, Rect2(Point2(0, 0), get_size()));
@@ -286,7 +310,7 @@ void Label::_notification(int p_what) {
if (lines_visible > 0) {
switch (valign) {
case VALIGN_TOP: {
- //nothing
+ // Nothing.
} break;
case VALIGN_CENTER: {
vbegin = (size.y - (total_h - line_spacing)) / 2;
@@ -331,83 +355,84 @@ void Label::_notification(int p_what) {
Vector2 ofs;
ofs.y = style->get_offset().y + vbegin;
for (int i = lines_skipped; i < last_line; i++) {
+ Size2 line_size = TS->shaped_text_get_size(lines_rid[i]);
ofs.x = 0;
ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + font->get_spacing(Font::SPACING_TOP);
switch (align) {
case ALIGN_FILL:
- case ALIGN_LEFT: {
- if (rtl) {
- ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - TS->shaped_text_get_size(lines_rid[i]).x);
+ if (rtl && autowrap_mode != AUTOWRAP_OFF) {
+ ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width);
} else {
ofs.x = style->get_offset().x;
}
+ break;
+ case ALIGN_LEFT: {
+ ofs.x = style->get_offset().x;
} break;
case ALIGN_CENTER: {
- ofs.x = int(size.width - TS->shaped_text_get_size(lines_rid[i]).x) / 2;
+ ofs.x = int(size.width - line_size.width) / 2;
} break;
case ALIGN_RIGHT: {
- if (rtl) {
- ofs.x = style->get_offset().x;
- } else {
- ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - TS->shaped_text_get_size(lines_rid[i]).x);
- }
+ ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width);
} break;
}
const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]);
const TextServer::Glyph *glyphs = visual.ptr();
int gl_size = visual.size();
+ TextServer::TrimData trim_data = TS->shaped_text_get_trim_data(lines_rid[i]);
+
+ // Draw RTL ellipsis string when necessary.
+ if (rtl && trim_data.ellipsis_pos >= 0) {
+ for (int gl_idx = trim_data.ellipsis_glyph_buf.size() - 1; gl_idx >= 0; gl_idx--) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
+ //Draw glyph outlines and shadow.
+ draw_glyph(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, ofs, shadow_ofs);
+ ofs.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
+ }
+ }
+ }
- float x = ofs.x;
- int outlines_drawn = glyhps_drawn;
+ // Draw main text.
for (int j = 0; j < gl_size; j++) {
for (int k = 0; k < glyphs[j].repeat; k++) {
- if (glyphs[j].font_rid != RID()) {
- if (font_shadow_color.a > 0) {
- TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + shadow_ofs, glyphs[j].index, font_shadow_color);
- if (shadow_outline_size > 0) {
- //draw shadow
- TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, shadow_outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + Vector2(-shadow_ofs.x, shadow_ofs.y), glyphs[j].index, font_shadow_color);
- TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, shadow_outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + Vector2(shadow_ofs.x, -shadow_ofs.y), glyphs[j].index, font_shadow_color);
- TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, shadow_outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + Vector2(-shadow_ofs.x, -shadow_ofs.y), glyphs[j].index, font_shadow_color);
+ if (visible_glyphs != -1) {
+ if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ if (glyhps_drawn >= visible_glyphs) {
+ return;
}
}
- if (font_outline_color.a != 0.0 && outline_size > 0) {
- TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off), glyphs[j].index, font_outline_color);
- }
}
- ofs.x += glyphs[j].advance;
- }
- if (visible_glyphs != -1) {
- if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- outlines_drawn++;
- if (outlines_drawn >= visible_glyphs) {
- break;
+
+ // Trim when necessary.
+ if (trim_data.trim_pos >= 0) {
+ if (rtl) {
+ if (j < trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ continue;
+ }
+ } else {
+ if (j >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ break;
+ }
}
}
- }
- }
- ofs.x = x;
- for (int j = 0; j < gl_size; j++) {
- for (int k = 0; k < glyphs[j].repeat; k++) {
- if (glyphs[j].font_rid != RID()) {
- TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off), glyphs[j].index, font_color);
- } else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- TS->draw_hex_code_box(ci, glyphs[j].font_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off), glyphs[j].index, font_color);
- }
+ // Draw glyph outlines and shadow.
+ draw_glyph(glyphs[j], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, ofs, shadow_ofs);
ofs.x += glyphs[j].advance;
+ glyhps_drawn++;
}
- if (visible_glyphs != -1) {
- if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- glyhps_drawn++;
- if (glyhps_drawn >= visible_glyphs) {
- return;
- }
+ }
+ // Draw LTR ellipsis string when necessary.
+ if (!rtl && trim_data.ellipsis_pos >= 0) {
+ for (int gl_idx = 0; gl_idx < trim_data.ellipsis_glyph_buf.size(); gl_idx++) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
+ //Draw glyph outlines and shadow.
+ draw_glyph(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, ofs, shadow_ofs);
+ ofs.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
}
}
}
-
ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing + font->get_spacing(Font::SPACING_BOTTOM);
}
}
@@ -624,6 +649,9 @@ void Label::set_visible_characters(int p_amount) {
} else {
percent_visible = 1.0;
}
+ if (p_amount == -1) {
+ lines_dirty = true;
+ }
update();
}
@@ -635,7 +663,7 @@ void Label::set_percent_visible(float p_percent) {
if (p_percent < 0 || p_percent >= 1) {
visible_chars = -1;
percent_visible = 1;
-
+ lines_dirty = true;
} else {
visible_chars = get_total_character_count() * p_percent;
percent_visible = p_percent;
@@ -793,7 +821,7 @@ void Label::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "valign", PROPERTY_HINT_ENUM, "Top,Center,Bottom,Fill"), "set_valign", "get_valign");
ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim nothing,Trim characters,Trim words,Ellipsis,Word ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1", PROPERTY_USAGE_EDITOR), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 4d3a4ea334..5ff92c6ff6 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -158,8 +158,6 @@
#include "scene/resources/physics_material.h"
#include "scene/resources/polygon_path_finder.h"
#include "scene/resources/primitive_meshes.h"
-#include "scene/resources/ray_shape_2d.h"
-#include "scene/resources/ray_shape_3d.h"
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/resource_format_text.h"
#include "scene/resources/segment_shape_2d.h"
@@ -747,7 +745,6 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
GDREGISTER_VIRTUAL_CLASS(Shape3D);
- GDREGISTER_CLASS(RayShape3D);
GDREGISTER_CLASS(SphereShape3D);
GDREGISTER_CLASS(BoxShape3D);
GDREGISTER_CLASS(CapsuleShape3D);
@@ -828,7 +825,6 @@ void register_scene_types() {
GDREGISTER_VIRTUAL_CLASS(Shape2D);
GDREGISTER_CLASS(LineShape2D);
GDREGISTER_CLASS(SegmentShape2D);
- GDREGISTER_CLASS(RayShape2D);
GDREGISTER_CLASS(CircleShape2D);
GDREGISTER_CLASS(RectangleShape2D);
GDREGISTER_CLASS(CapsuleShape2D);
@@ -948,7 +944,6 @@ void register_scene_types() {
ClassDB::add_compatibility_class("ProceduralSky", "Sky");
ClassDB::add_compatibility_class("ProximityGroup", "ProximityGroup3D");
ClassDB::add_compatibility_class("RayCast", "RayCast3D");
- ClassDB::add_compatibility_class("RayShape", "RayShape3D");
ClassDB::add_compatibility_class("RemoteTransform", "RemoteTransform3D");
ClassDB::add_compatibility_class("RigidBody", "RigidBody3D");
ClassDB::add_compatibility_class("Shape", "Shape3D");
diff --git a/scene/resources/ray_shape_2d.cpp b/scene/resources/ray_shape_2d.cpp
deleted file mode 100644
index fb8f4b9985..0000000000
--- a/scene/resources/ray_shape_2d.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*************************************************************************/
-/* ray_shape_2d.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "ray_shape_2d.h"
-
-#include "servers/physics_server_2d.h"
-#include "servers/rendering_server.h"
-
-void RayShape2D::_update_shape() {
- Dictionary d;
- d["length"] = length;
- d["slips_on_slope"] = slips_on_slope;
- PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), d);
- emit_changed();
-}
-
-void RayShape2D::draw(const RID &p_to_rid, const Color &p_color) {
- const Vector2 target_position = Vector2(0, get_length());
-
- const float max_arrow_size = 6;
- const float line_width = 1.4;
- bool no_line = target_position.length() < line_width;
- float arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size);
-
- if (no_line) {
- arrow_size = target_position.length();
- } else {
- RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), target_position - target_position.normalized() * arrow_size, p_color, line_width);
- }
-
- Transform2D xf;
- xf.rotate(target_position.angle());
- xf.translate(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0));
-
- Vector<Vector2> pts;
- pts.push_back(xf.xform(Vector2(arrow_size, 0)));
- pts.push_back(xf.xform(Vector2(0, 0.5 * arrow_size)));
- pts.push_back(xf.xform(Vector2(0, -0.5 * arrow_size)));
-
- Vector<Color> cols;
- for (int i = 0; i < 3; i++) {
- cols.push_back(p_color);
- }
-
- RS::get_singleton()->canvas_item_add_primitive(p_to_rid, pts, cols, Vector<Point2>(), RID());
-}
-
-Rect2 RayShape2D::get_rect() const {
- Rect2 rect;
- rect.position = Vector2();
- rect.expand_to(Vector2(0, length));
- rect = rect.grow(Math_SQRT12 * 4);
- return rect;
-}
-
-real_t RayShape2D::get_enclosing_radius() const {
- return length;
-}
-
-void RayShape2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_length", "length"), &RayShape2D::set_length);
- ClassDB::bind_method(D_METHOD("get_length"), &RayShape2D::get_length);
-
- ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape2D::set_slips_on_slope);
- ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape2D::get_slips_on_slope);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length"), "set_length", "get_length");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope");
-}
-
-void RayShape2D::set_length(real_t p_length) {
- length = p_length;
- _update_shape();
-}
-
-real_t RayShape2D::get_length() const {
- return length;
-}
-
-void RayShape2D::set_slips_on_slope(bool p_active) {
- slips_on_slope = p_active;
- _update_shape();
-}
-
-bool RayShape2D::get_slips_on_slope() const {
- return slips_on_slope;
-}
-
-RayShape2D::RayShape2D() :
- Shape2D(PhysicsServer2D::get_singleton()->ray_shape_create()) {
- _update_shape();
-}
diff --git a/scene/resources/ray_shape_2d.h b/scene/resources/ray_shape_2d.h
deleted file mode 100644
index 56ecfa2722..0000000000
--- a/scene/resources/ray_shape_2d.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*************************************************************************/
-/* ray_shape_2d.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef RAY_SHAPE_2D_H
-#define RAY_SHAPE_2D_H
-
-#include "scene/resources/shape_2d.h"
-
-class RayShape2D : public Shape2D {
- GDCLASS(RayShape2D, Shape2D);
-
- real_t length = 20.0;
- bool slips_on_slope = false;
-
- void _update_shape();
-
-protected:
- static void _bind_methods();
-
-public:
- void set_length(real_t p_length);
- real_t get_length() const;
-
- void set_slips_on_slope(bool p_active);
- bool get_slips_on_slope() const;
-
- virtual void draw(const RID &p_to_rid, const Color &p_color) override;
- virtual Rect2 get_rect() const override;
- virtual real_t get_enclosing_radius() const override;
-
- RayShape2D();
-};
-
-#endif // RAY_SHAPE_2D_H
diff --git a/scene/resources/ray_shape_3d.cpp b/scene/resources/ray_shape_3d.cpp
deleted file mode 100644
index 5446b4daab..0000000000
--- a/scene/resources/ray_shape_3d.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*************************************************************************/
-/* ray_shape_3d.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "ray_shape_3d.h"
-
-#include "servers/physics_server_3d.h"
-
-Vector<Vector3> RayShape3D::get_debug_mesh_lines() const {
- Vector<Vector3> points;
- points.push_back(Vector3());
- points.push_back(Vector3(0, 0, get_length()));
-
- return points;
-}
-
-real_t RayShape3D::get_enclosing_radius() const {
- return length;
-}
-
-void RayShape3D::_update_shape() {
- Dictionary d;
- d["length"] = length;
- d["slips_on_slope"] = slips_on_slope;
- PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
- Shape3D::_update_shape();
-}
-
-void RayShape3D::set_length(float p_length) {
- length = p_length;
- _update_shape();
- notify_change_to_owners();
-}
-
-float RayShape3D::get_length() const {
- return length;
-}
-
-void RayShape3D::set_slips_on_slope(bool p_active) {
- slips_on_slope = p_active;
- _update_shape();
- notify_change_to_owners();
-}
-
-bool RayShape3D::get_slips_on_slope() const {
- return slips_on_slope;
-}
-
-void RayShape3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_length", "length"), &RayShape3D::set_length);
- ClassDB::bind_method(D_METHOD("get_length"), &RayShape3D::get_length);
-
- ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape3D::set_slips_on_slope);
- ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape3D::get_slips_on_slope);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0,4096,0.001"), "set_length", "get_length");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope");
-}
-
-RayShape3D::RayShape3D() :
- Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_RAY)) {
- /* Code copied from setters to prevent the use of uninitialized variables */
- _update_shape();
- notify_change_to_owners();
-}
diff --git a/scene/resources/ray_shape_3d.h b/scene/resources/ray_shape_3d.h
deleted file mode 100644
index 2da6311321..0000000000
--- a/scene/resources/ray_shape_3d.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*************************************************************************/
-/* ray_shape_3d.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef RAY_SHAPE_H
-#define RAY_SHAPE_H
-#include "scene/resources/shape_3d.h"
-
-class RayShape3D : public Shape3D {
- GDCLASS(RayShape3D, Shape3D);
- float length = 1.0;
- bool slips_on_slope = false;
-
-protected:
- static void _bind_methods();
- virtual void _update_shape() override;
-
-public:
- void set_length(float p_length);
- float get_length() const;
-
- void set_slips_on_slope(bool p_active);
- bool get_slips_on_slope() const;
-
- virtual Vector<Vector3> get_debug_mesh_lines() const override;
- virtual real_t get_enclosing_radius() const override;
-
- RayShape3D();
-};
-#endif // RAY_SHAPE_H
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 87371224e0..7d5868e3a6 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -87,9 +87,6 @@ void StyleBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_margin", "margin", "offset"), &StyleBox::set_default_margin);
ClassDB::bind_method(D_METHOD("get_default_margin", "margin"), &StyleBox::get_default_margin);
- //ClassDB::bind_method(D_METHOD("set_default_margin"),&StyleBox::set_default_margin);
- //ClassDB::bind_method(D_METHOD("get_default_margin"),&StyleBox::get_default_margin);
-
ClassDB::bind_method(D_METHOD("get_margin", "margin"), &StyleBox::get_margin);
ClassDB::bind_method(D_METHOD("get_minimum_size"), &StyleBox::get_minimum_size);
ClassDB::bind_method(D_METHOD("get_center_size"), &StyleBox::get_center_size);
@@ -464,12 +461,12 @@ bool StyleBoxFlat::is_anti_aliased() const {
return anti_aliased;
}
-void StyleBoxFlat::set_aa_size(const int &p_aa_size) {
- aa_size = CLAMP(p_aa_size, 1, 5);
+void StyleBoxFlat::set_aa_size(const real_t &p_aa_size) {
+ aa_size = CLAMP(p_aa_size, 0.01, 10);
emit_changed();
}
-int StyleBoxFlat::get_aa_size() const {
+float StyleBoxFlat::get_aa_size() const {
return aa_size;
}
@@ -486,31 +483,32 @@ Size2 StyleBoxFlat::get_center_size() const {
return Size2();
}
-inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_rect, const int corner_radius[4], int *inner_corner_radius) {
- int border_left = inner_rect.position.x - style_rect.position.x;
- int border_top = inner_rect.position.y - style_rect.position.y;
- int border_right = style_rect.size.width - inner_rect.size.width - border_left;
- int border_bottom = style_rect.size.height - inner_rect.size.height - border_top;
+inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_rect, const real_t corner_radius[4], real_t *inner_corner_radius) {
+ real_t border_left = inner_rect.position.x - style_rect.position.x;
+ real_t border_top = inner_rect.position.y - style_rect.position.y;
+ real_t border_right = style_rect.size.width - inner_rect.size.width - border_left;
+ real_t border_bottom = style_rect.size.height - inner_rect.size.height - border_top;
+
+ real_t rad;
- int rad;
- //tl
+ // Top left.
rad = MIN(border_top, border_left);
inner_corner_radius[0] = MAX(corner_radius[0] - rad, 0);
- //tr
+ // Top right;
rad = MIN(border_top, border_right);
inner_corner_radius[1] = MAX(corner_radius[1] - rad, 0);
- //br
+ // Bottom right.
rad = MIN(border_bottom, border_right);
inner_corner_radius[2] = MAX(corner_radius[2] - rad, 0);
- //bl
+ // Bottom left.
rad = MIN(border_bottom, border_left);
inner_corner_radius[3] = MAX(corner_radius[3] - rad, 0);
}
-inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 &style_rect, const int corner_radius[4],
+inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 &style_rect, const real_t corner_radius[4],
const Rect2 &ring_rect, const Rect2 &inner_rect, const Color &inner_color, const Color &outer_color, const int corner_detail, const bool fill_center = false) {
int vert_offset = verts.size();
if (!vert_offset) {
@@ -519,17 +517,17 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail;
- int ring_corner_radius[4];
+ real_t ring_corner_radius[4];
set_inner_corner_radius(style_rect, ring_rect, corner_radius, ring_corner_radius);
- //corner radius center points
+ // Corner radius center points.
Vector<Point2> outer_points;
outer_points.push_back(ring_rect.position + Vector2(ring_corner_radius[0], ring_corner_radius[0])); //tl
outer_points.push_back(Point2(ring_rect.position.x + ring_rect.size.x - ring_corner_radius[1], ring_rect.position.y + ring_corner_radius[1])); //tr
outer_points.push_back(ring_rect.position + ring_rect.size - Vector2(ring_corner_radius[2], ring_corner_radius[2])); //br
outer_points.push_back(Point2(ring_rect.position.x + ring_corner_radius[3], ring_rect.position.y + ring_rect.size.y - ring_corner_radius[3])); //bl
- int inner_corner_radius[4];
+ real_t inner_corner_radius[4];
set_inner_corner_radius(style_rect, inner_rect, corner_radius, inner_corner_radius);
Vector<Point2> inner_points;
@@ -538,11 +536,11 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
inner_points.push_back(inner_rect.position + inner_rect.size - Vector2(inner_corner_radius[2], inner_corner_radius[2])); //br
inner_points.push_back(Point2(inner_rect.position.x + inner_corner_radius[3], inner_rect.position.y + inner_rect.size.y - inner_corner_radius[3])); //bl
- //calculate the vert array
+ // Calculate the vertices.
for (int corner_index = 0; corner_index < 4; corner_index++) {
for (int detail = 0; detail <= adapted_corner_detail; detail++) {
for (int inner_outer = 0; inner_outer < 2; inner_outer++) {
- float radius;
+ real_t radius;
Color color;
Point2 corner_point;
if (inner_outer == 0) {
@@ -564,7 +562,7 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
int ring_vert_count = verts.size() - vert_offset;
- //fill the indices and the colors for the border
+ // Fill the indices and the colors for the border.
for (int i = 0; i < ring_vert_count; i++) {
indices.push_back(vert_offset + ((i + 0) % ring_vert_count));
indices.push_back(vert_offset + ((i + 2) % ring_vert_count));
@@ -572,14 +570,14 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
}
if (fill_center) {
- //fill the indices and the colors for the center
+ //Fill the indices and the colors for the center.
for (int index = 0; index < ring_vert_count / 2; index += 2) {
int i = index;
- //poly 1
+ // Polygon 1.
indices.push_back(vert_offset + i);
indices.push_back(vert_offset + ring_vert_count - 4 - i);
indices.push_back(vert_offset + i + 2);
- //poly 2
+ // Polygon 2.
indices.push_back(vert_offset + i);
indices.push_back(vert_offset + ring_vert_count - 2 - i);
indices.push_back(vert_offset + ring_vert_count - 4 - i);
@@ -587,20 +585,20 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
}
}
-inline void adapt_values(int p_index_a, int p_index_b, int *adapted_values, const int *p_values, const real_t p_width, const int p_max_a, const int p_max_b) {
+inline void adapt_values(int p_index_a, int p_index_b, real_t *adapted_values, const real_t *p_values, const real_t p_width, const real_t p_max_a, const real_t p_max_b) {
if (p_values[p_index_a] + p_values[p_index_b] > p_width) {
- float factor;
- int newValue;
+ real_t factor;
+ real_t new_value;
- factor = (float)p_width / (float)(p_values[p_index_a] + p_values[p_index_b]);
+ factor = (real_t)p_width / (real_t)(p_values[p_index_a] + p_values[p_index_b]);
- newValue = (int)(p_values[p_index_a] * factor);
- if (newValue < adapted_values[p_index_a]) {
- adapted_values[p_index_a] = newValue;
+ new_value = (p_values[p_index_a] * factor);
+ if (new_value < adapted_values[p_index_a]) {
+ adapted_values[p_index_a] = new_value;
}
- newValue = (int)(p_values[p_index_b] * factor);
- if (newValue < adapted_values[p_index_b]) {
- adapted_values[p_index_b] = newValue;
+ new_value = (p_values[p_index_b] * factor);
+ if (new_value < adapted_values[p_index_b]) {
+ adapted_values[p_index_b] = new_value;
}
} else {
adapted_values[p_index_a] = MIN(p_values[p_index_a], adapted_values[p_index_a]);
@@ -623,7 +621,6 @@ Rect2 StyleBoxFlat::get_draw_rect(const Rect2 &p_rect) const {
}
void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
- //PREPARATIONS
bool draw_border = (border_width[0] > 0) || (border_width[1] > 0) || (border_width[2] > 0) || (border_width[3] > 0);
bool draw_shadow = (shadow_size > 0);
if (!draw_border && !draw_center && !draw_shadow) {
@@ -637,7 +634,6 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
bool aa_on = rounded_corners && anti_aliased;
- float aa_size_grow = 0.5 * ((float)aa_size + 1.0);
bool blend_on = blend_border && draw_border;
@@ -645,15 +641,15 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
Color border_color_blend = (draw_center ? bg_color : border_color_alpha);
Color border_color_inner = blend_on ? border_color_blend : border_color;
- //adapt borders (prevent weird overlapping/glitchy drawings)
- int width = MAX(style_rect.size.width, 0);
- int height = MAX(style_rect.size.height, 0);
- int adapted_border[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
+ // Adapt borders (prevent weird overlapping/glitchy drawings).
+ real_t width = MAX(style_rect.size.width, 0);
+ real_t height = MAX(style_rect.size.height, 0);
+ real_t adapted_border[4] = { 1000000.0, 1000000.0, 1000000.0, 1000000.0 };
adapt_values(SIDE_TOP, SIDE_BOTTOM, adapted_border, border_width, height, height, height);
adapt_values(SIDE_LEFT, SIDE_RIGHT, adapted_border, border_width, width, width, width);
- //adapt corners (prevent weird overlapping/glitchy drawings)
- int adapted_corner[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
+ // Adapt corners (prevent weird overlapping/glitchy drawings).
+ real_t adapted_corner[4] = { 1000000.0, 1000000.0, 1000000.0, 1000000.0 };
adapt_values(CORNER_TOP_RIGHT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]);
adapt_values(CORNER_TOP_LEFT, CORNER_BOTTOM_LEFT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]);
adapt_values(CORNER_TOP_LEFT, CORNER_TOP_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[SIDE_RIGHT], width - adapted_border[SIDE_LEFT]);
@@ -665,7 +661,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
if (aa_on) {
for (int i = 0; i < 4; i++) {
if (border_width[i] > 0) {
- border_style_rect = border_style_rect.grow_side((Side)i, -aa_size_grow);
+ border_style_rect = border_style_rect.grow_side((Side)i, -aa_size);
}
}
}
@@ -675,7 +671,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
Vector<Color> colors;
Vector<Point2> uvs;
- //DRAW SHADOW
+ // Create shadow
if (draw_shadow) {
Rect2 shadow_inner_rect = style_rect;
shadow_inner_rect.position += shadow_offset;
@@ -694,35 +690,35 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
}
}
- //DRAW border
- if (draw_border) {
+ // Create border (no AA).
+ if (draw_border && !aa_on) {
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
border_style_rect, infill_rect, border_color_inner, border_color, corner_detail);
}
- //DRAW INFILL
+ // Create infill (no AA).
if (draw_center && (!aa_on || blend_on || !draw_border)) {
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
infill_rect, infill_rect, bg_color, bg_color, corner_detail, true);
}
if (aa_on) {
- int aa_border_width[4];
- int aa_fill_width[4];
+ real_t aa_border_width[4];
+ real_t aa_fill_width[4];
if (draw_border) {
for (int i = 0; i < 4; i++) {
if (border_width[i] > 0) {
- aa_border_width[i] = aa_size_grow;
+ aa_border_width[i] = aa_size;
aa_fill_width[i] = 0;
} else {
aa_border_width[i] = 0;
- aa_fill_width[i] = aa_size_grow;
+ aa_fill_width[i] = aa_size;
}
}
} else {
for (int i = 0; i < 4; i++) {
aa_border_width[i] = 0;
- aa_fill_width[i] = aa_size_grow;
+ aa_fill_width[i] = aa_size;
}
}
@@ -731,45 +727,58 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
if (draw_center) {
if (!blend_on && draw_border) {
- //DRAW INFILL WITHIN BORDER AA
+ Rect2 infill_inner_rect_aa = infill_inner_rect.grow_individual(aa_border_width[SIDE_LEFT], aa_border_width[SIDE_TOP],
+ aa_border_width[SIDE_RIGHT], aa_border_width[SIDE_BOTTOM]);
+ // Create infill within AA border.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
- infill_inner_rect, infill_inner_rect, bg_color, bg_color, corner_detail, true);
+ infill_inner_rect_aa, infill_inner_rect_aa, bg_color, bg_color, corner_detail, true);
}
if (!blend_on || !draw_border) {
- Rect2 infill_aa_rect = infill_rect.grow_individual(aa_fill_width[SIDE_LEFT], aa_fill_width[SIDE_TOP],
+ Rect2 infill_rect_aa = infill_rect.grow_individual(aa_fill_width[SIDE_LEFT], aa_fill_width[SIDE_TOP],
aa_fill_width[SIDE_RIGHT], aa_fill_width[SIDE_BOTTOM]);
Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0);
- //INFILL AA
+ // Create infill fake AA gradient.
draw_ring(verts, indices, colors, style_rect, adapted_corner,
- infill_aa_rect, infill_rect, bg_color, alpha_bg, corner_detail);
+ infill_rect_aa, infill_rect, bg_color, alpha_bg, corner_detail);
}
}
if (draw_border) {
+ Rect2 infill_rect_aa = infill_rect.grow_individual(aa_border_width[SIDE_LEFT], aa_border_width[SIDE_TOP],
+ aa_border_width[SIDE_RIGHT], aa_border_width[SIDE_BOTTOM]);
+ Rect2 style_rect_aa = style_rect.grow_individual(aa_border_width[SIDE_LEFT], aa_border_width[SIDE_TOP],
+ aa_border_width[SIDE_RIGHT], aa_border_width[SIDE_BOTTOM]);
+ Rect2 border_style_rect_aa = border_style_rect.grow_individual(aa_border_width[SIDE_LEFT], aa_border_width[SIDE_TOP],
+ aa_border_width[SIDE_RIGHT], aa_border_width[SIDE_BOTTOM]);
+
+ // Create border.
+ draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
+ border_style_rect_aa, ((blend_on) ? infill_rect : infill_rect_aa), border_color_inner, border_color, corner_detail);
+
if (!blend_on) {
- //DRAW INNER BORDER AA
+ // Create inner border fake AA gradient.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
- infill_rect, infill_inner_rect, border_color_blend, border_color, corner_detail);
+ infill_rect_aa, infill_rect, border_color_blend, border_color, corner_detail);
}
- //DRAW OUTER BORDER AA
+ // Create outer border fake AA gradient.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
- style_rect, border_style_rect, border_color, border_color_alpha, corner_detail);
+ style_rect_aa, border_style_rect_aa, border_color, border_color_alpha, corner_detail);
}
}
- //COMPUTE UV COORDINATES
- Rect2 uv_rect = style_rect.grow(aa_on ? aa_size_grow : 0);
+ // Compute UV coordinates.
+ Rect2 uv_rect = style_rect.grow(aa_on ? aa_size : 0);
uvs.resize(verts.size());
for (int i = 0; i < verts.size(); i++) {
uvs.write[i].x = (verts[i].x - uv_rect.position.x) / uv_rect.size.width;
uvs.write[i].y = (verts[i].y - uv_rect.position.y) / uv_rect.size.height;
}
- //DRAWING
+ // Draw stylebox.
RenderingServer *vs = RenderingServer::get_singleton();
vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors, uvs);
}
@@ -869,7 +878,7 @@ void StyleBoxFlat::_bind_methods() {
ADD_GROUP("Anti Aliasing", "anti_aliasing_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "anti_aliasing"), "set_anti_aliased", "is_anti_aliased");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "1,5,1"), "set_aa_size", "get_aa_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "0.01,10,0.001"), "set_aa_size", "get_aa_size");
}
StyleBoxFlat::StyleBoxFlat() {}
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index dd5c873a00..124521b915 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -143,9 +143,9 @@ class StyleBoxFlat : public StyleBox {
Color shadow_color = Color(0, 0, 0, 0.6);
Color border_color = Color(0.8, 0.8, 0.8);
- int border_width[4] = {};
- int expand_margin[4] = {};
- int corner_radius[4] = {};
+ real_t border_width[4] = {};
+ real_t expand_margin[4] = {};
+ real_t corner_radius[4] = {};
bool draw_center = true;
bool blend_border = false;
@@ -154,7 +154,7 @@ class StyleBoxFlat : public StyleBox {
int corner_detail = 8;
int shadow_size = 0;
Point2 shadow_offset;
- int aa_size = 1;
+ real_t aa_size = 0.625;
protected:
virtual float get_style_margin(Side p_side) const override;
@@ -162,27 +162,21 @@ protected:
void _validate_property(PropertyInfo &property) const override;
public:
- //Color
void set_bg_color(const Color &p_color);
Color get_bg_color() const;
- //Border Color
void set_border_color(const Color &p_color);
Color get_border_color() const;
- //BORDER
- //width
void set_border_width_all(int p_size);
int get_border_width_min() const;
void set_border_width(Side p_side, int p_width);
int get_border_width(Side p_side) const;
- //blend
void set_border_blend(bool p_blend);
bool get_border_blend() const;
- //CORNER
void set_corner_radius_all(int radius);
void set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_bottom_right, const int radius_bottom_left);
@@ -192,17 +186,14 @@ public:
void set_corner_detail(const int &p_corner_detail);
int get_corner_detail() const;
- //EXPANDS
void set_expand_margin_size(Side p_expand_side, float p_size);
void set_expand_margin_size_all(float p_expand_margin_size);
void set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom);
float get_expand_margin_size(Side p_expand_side) const;
- //DRAW CENTER
void set_draw_center(bool p_enabled);
bool is_draw_center_enabled() const;
- //SHADOW
void set_shadow_color(const Color &p_color);
Color get_shadow_color() const;
@@ -212,12 +203,10 @@ public:
void set_shadow_offset(const Point2 &p_offset);
Point2 get_shadow_offset() const;
- //ANTI_ALIASING
void set_anti_aliased(const bool &p_anti_aliased);
bool is_anti_aliased() const;
- //tempAA
- void set_aa_size(const int &p_aa_size);
- int get_aa_size() const;
+ void set_aa_size(const float &p_aa_size);
+ float get_aa_size() const;
virtual Size2 get_center_size() const override;
@@ -228,7 +217,7 @@ public:
~StyleBoxFlat();
};
-// just used to draw lines.
+// Just used to draw lines.
class StyleBoxLine : public StyleBox {
GDCLASS(StyleBoxLine, StyleBox);
Color color;
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index 5e60c7c4ed..0807a062f2 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -76,6 +76,11 @@ void TextLine::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justify,Word Justify,Trim Edge Spaces After Justify,Justify Only After Last Tab"), "set_flags", "get_flags");
+ ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &TextLine::set_text_overrun_behavior);
+ ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &TextLine::get_text_overrun_behavior);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
+
ClassDB::bind_method(D_METHOD("get_objects"), &TextLine::get_objects);
ClassDB::bind_method(D_METHOD("get_object_rect", "key"), &TextLine::get_object_rect);
@@ -93,6 +98,12 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_outline", "canvas", "pos", "outline_size", "color"), &TextLine::draw_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextLine::hit_test);
+
+ BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
}
void TextLine::_shape() {
@@ -100,7 +111,38 @@ void TextLine::_shape() {
if (!tab_stops.is_empty()) {
TS->shaped_text_tab_align(rid, tab_stops);
}
- if (align == HALIGN_FILL) {
+
+ uint8_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
+ if (overrun_behavior != OVERRUN_NO_TRIMMING) {
+ switch (overrun_behavior) {
+ case OVERRUN_TRIM_WORD_ELLIPSIS:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ break;
+ case OVERRUN_TRIM_ELLIPSIS:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ break;
+ case OVERRUN_TRIM_WORD:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ break;
+ case OVERRUN_TRIM_CHAR:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ break;
+ case OVERRUN_NO_TRIMMING:
+ break;
+ }
+
+ if (align == HALIGN_FILL) {
+ TS->shaped_text_fit_to_width(rid, width, flags);
+ overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
+ TS->shaped_text_overrun_trim_to_width(rid, width, overrun_flags);
+ } else {
+ TS->shaped_text_overrun_trim_to_width(rid, width, overrun_flags);
+ }
+ } else if (align == HALIGN_FILL) {
TS->shaped_text_fit_to_width(rid, width, flags);
}
dirty = false;
@@ -225,9 +267,20 @@ uint8_t TextLine::get_flags() const {
return flags;
}
+void TextLine::set_text_overrun_behavior(TextLine::OverrunBehavior p_behavior) {
+ if (overrun_behavior != p_behavior) {
+ overrun_behavior = p_behavior;
+ dirty = true;
+ }
+}
+
+TextLine::OverrunBehavior TextLine::get_text_overrun_behavior() const {
+ return overrun_behavior;
+}
+
void TextLine::set_width(float p_width) {
width = p_width;
- if (align == HALIGN_FILL) {
+ if (align == HALIGN_FILL || overrun_behavior != OVERRUN_NO_TRIMMING) {
dirty = true;
}
}
diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h
index b773bd05be..9ed9c2f177 100644
--- a/scene/resources/text_line.h
+++ b/scene/resources/text_line.h
@@ -39,6 +39,16 @@
class TextLine : public RefCounted {
GDCLASS(TextLine, RefCounted);
+public:
+ enum OverrunBehavior {
+ OVERRUN_NO_TRIMMING,
+ OVERRUN_TRIM_CHAR,
+ OVERRUN_TRIM_WORD,
+ OVERRUN_TRIM_ELLIPSIS,
+ OVERRUN_TRIM_WORD_ELLIPSIS,
+ };
+
+private:
RID rid;
int spacing_top = 0;
int spacing_bottom = 0;
@@ -48,6 +58,7 @@ class TextLine : public RefCounted {
float width = -1.0;
uint8_t flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
HAlign align = HALIGN_LEFT;
+ OverrunBehavior overrun_behavior = OVERRUN_TRIM_ELLIPSIS;
Vector<float> tab_stops;
@@ -87,6 +98,9 @@ public:
void set_flags(uint8_t p_flags);
uint8_t get_flags() const;
+ void set_text_overrun_behavior(OverrunBehavior p_behavior);
+ OverrunBehavior get_text_overrun_behavior() const;
+
void set_width(float p_width);
float get_width() const;
@@ -113,4 +127,6 @@ public:
~TextLine();
};
+VARIANT_ENUM_CAST(TextLine::OverrunBehavior);
+
#endif // TEXT_LINE_H
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index ffae551570..357411ae04 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -74,6 +74,11 @@ void TextParagraph::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Kashida Justify,Word Justify,Trim Edge Spaces After Justify,Justify Only After Last Tab,Break Mandatory,Break Words,Break Graphemes"), "set_flags", "get_flags");
+ ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &TextParagraph::set_text_overrun_behavior);
+ ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &TextParagraph::get_text_overrun_behavior);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
+
ClassDB::bind_method(D_METHOD("set_width", "width"), &TextParagraph::set_width);
ClassDB::bind_method(D_METHOD("get_width"), &TextParagraph::get_width);
@@ -88,6 +93,11 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_count"), &TextParagraph::get_line_count);
+ ClassDB::bind_method(D_METHOD("set_max_lines_visible", "max_lines_visible"), &TextParagraph::set_max_lines_visible);
+ ClassDB::bind_method(D_METHOD("get_max_lines_visible"), &TextParagraph::get_max_lines_visible);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible"), "set_max_lines_visible", "get_max_lines_visible");
+
ClassDB::bind_method(D_METHOD("get_line_objects", "line"), &TextParagraph::get_line_objects);
ClassDB::bind_method(D_METHOD("get_line_object_rect", "line", "key"), &TextParagraph::get_line_object_rect);
ClassDB::bind_method(D_METHOD("get_line_size", "line"), &TextParagraph::get_line_size);
@@ -114,14 +124,20 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_dropcap_outline", "canvas", "pos", "outline_size", "color"), &TextParagraph::draw_dropcap_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextParagraph::hit_test);
+
+ BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS);
+ BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS);
}
void TextParagraph::_shape_lines() {
- if (dirty_lines) {
- for (int i = 0; i < lines.size(); i++) {
- TS->free(lines[i]);
+ if (lines_dirty) {
+ for (int i = 0; i < lines_rid.size(); i++) {
+ TS->free(lines_rid[i]);
}
- lines.clear();
+ lines_rid.clear();
if (!tab_stops.is_empty()) {
TS->shaped_text_tab_align(rid, tab_stops);
@@ -153,13 +169,10 @@ void TextParagraph::_shape_lines() {
if (!tab_stops.is_empty()) {
TS->shaped_text_tab_align(line, tab_stops);
}
- if (align == HALIGN_FILL && (line_breaks.size() == 1 || i < line_breaks.size() - 1)) {
- TS->shaped_text_fit_to_width(line, width - h_offset, flags);
- }
dropcap_lines++;
v_offset -= h;
start = line_breaks[i].y;
- lines.push_back(line);
+ lines_rid.push_back(line);
}
}
// Use fixed for the rest of lines.
@@ -169,12 +182,69 @@ void TextParagraph::_shape_lines() {
if (!tab_stops.is_empty()) {
TS->shaped_text_tab_align(line, tab_stops);
}
- if (align == HALIGN_FILL && (line_breaks.size() == 1 || i < line_breaks.size() - 1)) {
- TS->shaped_text_fit_to_width(line, width, flags);
+ lines_rid.push_back(line);
+ }
+
+ uint8_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
+ if (overrun_behavior != OVERRUN_NO_TRIMMING) {
+ switch (overrun_behavior) {
+ case OVERRUN_TRIM_WORD_ELLIPSIS:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ break;
+ case OVERRUN_TRIM_ELLIPSIS:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_ADD_ELLIPSIS;
+ break;
+ case OVERRUN_TRIM_WORD:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ overrun_flags |= TextServer::OVERRUN_TRIM_WORD_ONLY;
+ break;
+ case OVERRUN_TRIM_CHAR:
+ overrun_flags |= TextServer::OVERRUN_TRIM;
+ break;
+ case OVERRUN_NO_TRIMMING:
+ break;
+ }
+ }
+
+ bool autowrap_enabled = ((flags & TextServer::BREAK_WORD_BOUND) == TextServer::BREAK_WORD_BOUND) || ((flags & TextServer::BREAK_GRAPHEME_BOUND) == TextServer::BREAK_GRAPHEME_BOUND);
+
+ // Fill after min_size calculation.
+ if (autowrap_enabled) {
+ int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
+ bool lines_hidden = visible_lines > 0 && visible_lines < lines_rid.size();
+ if (lines_hidden) {
+ overrun_flags |= TextServer::OVERRUN_ENFORCE_ELLIPSIS;
+ }
+ if (align == HALIGN_FILL) {
+ for (int i = 0; i < lines_rid.size(); i++) {
+ if (i < visible_lines - 1 || lines_rid.size() == 1) {
+ TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
+ } else if (i == (visible_lines - 1)) {
+ TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
+ }
+ }
+
+ } else if (lines_hidden) {
+ TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
+ }
+
+ } else {
+ // Autowrap disabled.
+ for (int i = 0; i < lines_rid.size(); i++) {
+ if (align == HALIGN_FILL) {
+ TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
+ overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
+ TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
+ TS->shaped_text_fit_to_width(lines_rid[i], width, flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
+ } else {
+ TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
+ }
}
- lines.push_back(line);
}
- dirty_lines = false;
+ lines_dirty = false;
}
}
@@ -184,8 +254,8 @@ RID TextParagraph::get_rid() const {
RID TextParagraph::get_line_rid(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), RID());
- return lines[p_line];
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), RID());
+ return lines_rid[p_line];
}
RID TextParagraph::get_dropcap_rid() const {
@@ -195,10 +265,10 @@ RID TextParagraph::get_dropcap_rid() const {
void TextParagraph::clear() {
spacing_top = 0;
spacing_bottom = 0;
- for (int i = 0; i < lines.size(); i++) {
- TS->free(lines[i]);
+ for (int i = 0; i < lines_rid.size(); i++) {
+ TS->free(lines_rid[i]);
}
- lines.clear();
+ lines_rid.clear();
TS->shaped_text_clear(rid);
TS->shaped_text_clear(dropcap_rid);
}
@@ -206,7 +276,7 @@ void TextParagraph::clear() {
void TextParagraph::set_preserve_invalid(bool p_enabled) {
TS->shaped_text_set_preserve_invalid(rid, p_enabled);
TS->shaped_text_set_preserve_invalid(dropcap_rid, p_enabled);
- dirty_lines = true;
+ lines_dirty = true;
}
bool TextParagraph::get_preserve_invalid() const {
@@ -216,7 +286,7 @@ bool TextParagraph::get_preserve_invalid() const {
void TextParagraph::set_preserve_control(bool p_enabled) {
TS->shaped_text_set_preserve_control(rid, p_enabled);
TS->shaped_text_set_preserve_control(dropcap_rid, p_enabled);
- dirty_lines = true;
+ lines_dirty = true;
}
bool TextParagraph::get_preserve_control() const {
@@ -226,7 +296,7 @@ bool TextParagraph::get_preserve_control() const {
void TextParagraph::set_direction(TextServer::Direction p_direction) {
TS->shaped_text_set_direction(rid, p_direction);
TS->shaped_text_set_direction(dropcap_rid, p_direction);
- dirty_lines = true;
+ lines_dirty = true;
}
TextServer::Direction TextParagraph::get_direction() const {
@@ -237,7 +307,7 @@ TextServer::Direction TextParagraph::get_direction() const {
void TextParagraph::set_orientation(TextServer::Orientation p_orientation) {
TS->shaped_text_set_orientation(rid, p_orientation);
TS->shaped_text_set_orientation(dropcap_rid, p_orientation);
- dirty_lines = true;
+ lines_dirty = true;
}
TextServer::Orientation TextParagraph::get_orientation() const {
@@ -250,14 +320,14 @@ bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts,
TS->shaped_text_clear(dropcap_rid);
dropcap_margins = p_dropcap_margins;
bool res = TS->shaped_text_add_string(dropcap_rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
- dirty_lines = true;
+ lines_dirty = true;
return res;
}
void TextParagraph::clear_dropcap() {
dropcap_margins = Rect2();
TS->shaped_text_clear(dropcap_rid);
- dirty_lines = true;
+ lines_dirty = true;
}
bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
@@ -265,7 +335,7 @@ bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, i
bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language);
spacing_top = p_fonts->get_spacing(Font::SPACING_TOP);
spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM);
- dirty_lines = true;
+ lines_dirty = true;
return res;
}
@@ -287,18 +357,18 @@ void TextParagraph::_set_bidi_override(const Array &p_override) {
void TextParagraph::set_bidi_override(const Vector<Vector2i> &p_override) {
TS->shaped_text_set_bidi_override(rid, p_override);
- dirty_lines = true;
+ lines_dirty = true;
}
bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
- dirty_lines = true;
+ lines_dirty = true;
return res;
}
bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
- dirty_lines = true;
+ lines_dirty = true;
return res;
}
@@ -306,7 +376,7 @@ void TextParagraph::set_align(HAlign p_align) {
if (align != p_align) {
if (align == HALIGN_FILL || p_align == HALIGN_FILL) {
align = p_align;
- dirty_lines = true;
+ lines_dirty = true;
} else {
align = p_align;
}
@@ -319,13 +389,13 @@ HAlign TextParagraph::get_align() const {
void TextParagraph::tab_align(const Vector<float> &p_tab_stops) {
tab_stops = p_tab_stops;
- dirty_lines = true;
+ lines_dirty = true;
}
void TextParagraph::set_flags(uint8_t p_flags) {
if (flags != p_flags) {
flags = p_flags;
- dirty_lines = true;
+ lines_dirty = true;
}
}
@@ -333,10 +403,21 @@ uint8_t TextParagraph::get_flags() const {
return flags;
}
+void TextParagraph::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) {
+ if (overrun_behavior != p_behavior) {
+ overrun_behavior = p_behavior;
+ lines_dirty = true;
+ }
+}
+
+TextParagraph::OverrunBehavior TextParagraph::get_text_overrun_behavior() const {
+ return overrun_behavior;
+}
+
void TextParagraph::set_width(float p_width) {
if (width != p_width) {
width = p_width;
- dirty_lines = true;
+ lines_dirty = true;
}
}
@@ -356,9 +437,9 @@ Size2 TextParagraph::get_non_wraped_size() const {
Size2 TextParagraph::get_size() const {
const_cast<TextParagraph *>(this)->_shape_lines();
Size2 size;
- for (int i = 0; i < lines.size(); i++) {
- Size2 lsize = TS->shaped_text_get_size(lines[i]);
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ for (int i = 0; i < lines_rid.size(); i++) {
+ Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
size.x = MAX(size.x, lsize.x);
size.y += lsize.y + spacing_top + spacing_bottom;
} else {
@@ -371,22 +452,33 @@ Size2 TextParagraph::get_size() const {
int TextParagraph::get_line_count() const {
const_cast<TextParagraph *>(this)->_shape_lines();
- return lines.size();
+ return lines_rid.size();
+}
+
+void TextParagraph::set_max_lines_visible(int p_lines) {
+ if (p_lines != max_lines_visible) {
+ max_lines_visible = p_lines;
+ lines_dirty = true;
+ }
+}
+
+int TextParagraph::get_max_lines_visible() const {
+ return max_lines_visible;
}
Array TextParagraph::get_line_objects(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Array());
- return TS->shaped_text_get_objects(lines[p_line]);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Array());
+ return TS->shaped_text_get_objects(lines_rid[p_line]);
}
Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Rect2());
- Rect2 xrect = TS->shaped_text_get_object_rect(lines[p_line], p_key);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Rect2());
+ Rect2 xrect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
for (int i = 0; i < p_line; i++) {
- Size2 lsize = TS->shaped_text_get_size(lines[i]);
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
xrect.position.y += lsize.y + spacing_top + spacing_bottom;
} else {
xrect.position.x += lsize.x + spacing_top + spacing_bottom;
@@ -397,48 +489,48 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
Size2 TextParagraph::get_line_size(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Size2());
- if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- return Size2(TS->shaped_text_get_size(lines[p_line]).x, TS->shaped_text_get_size(lines[p_line]).y + spacing_top + spacing_bottom);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Size2());
+ if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
+ return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y + spacing_top + spacing_bottom);
} else {
- return Size2(TS->shaped_text_get_size(lines[p_line]).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(lines[p_line]).y);
+ return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x + spacing_top + spacing_bottom, TS->shaped_text_get_size(lines_rid[p_line]).y);
}
}
Vector2i TextParagraph::get_line_range(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), Vector2i());
- return TS->shaped_text_get_range(lines[p_line]);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Vector2i());
+ return TS->shaped_text_get_range(lines_rid[p_line]);
}
float TextParagraph::get_line_ascent(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f);
- return TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ return TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
}
float TextParagraph::get_line_descent(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f);
- return TS->shaped_text_get_descent(lines[p_line]) + spacing_bottom;
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ return TS->shaped_text_get_descent(lines_rid[p_line]) + spacing_bottom;
}
float TextParagraph::get_line_width(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f);
- return TS->shaped_text_get_width(lines[p_line]);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ return TS->shaped_text_get_width(lines_rid[p_line]);
}
float TextParagraph::get_line_underline_position(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f);
- return TS->shaped_text_get_underline_position(lines[p_line]);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ return TS->shaped_text_get_underline_position(lines_rid[p_line]);
}
float TextParagraph::get_line_underline_thickness(int p_line) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND_V(p_line < 0 || p_line >= lines.size(), 0.f);
- return TS->shaped_text_get_underline_thickness(lines[p_line]);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+ return TS->shaped_text_get_underline_thickness(lines_rid[p_line]);
}
Size2 TextParagraph::get_dropcap_size() const {
@@ -472,11 +564,13 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
TS->shaped_text_draw(dropcap_rid, p_canvas, dc_off + Vector2(0, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.size.y + dropcap_margins.position.y / 2), -1, -1, p_dc_color);
}
- for (int i = 0; i < lines.size(); i++) {
+ int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
+
+ for (int i = 0; i < lines_visible; i++) {
float l_width = width;
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
if (i <= dropcap_lines) {
if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -485,7 +579,7 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
}
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
if (i <= dropcap_lines) {
if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -493,21 +587,29 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
l_width -= h_offset;
}
}
- float length = TS->shaped_text_get_width(lines[i]);
+ float length = TS->shaped_text_get_width(lines_rid[i]);
if (width > 0) {
switch (align) {
case HALIGN_FILL:
+ if (TS->shaped_text_get_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ break;
case HALIGN_LEFT:
break;
case HALIGN_CENTER: {
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x += Math::floor((l_width - length) / 2.0);
} else {
ofs.y += Math::floor((l_width - length) / 2.0);
}
} break;
case HALIGN_RIGHT: {
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x += l_width - length;
} else {
ofs.y += l_width - length;
@@ -516,18 +618,18 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
}
}
float clip_l;
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
clip_l = MAX(0, p_pos.y - ofs.y);
}
- TS->shaped_text_draw(lines[i], p_canvas, ofs, clip_l, clip_l + l_width, p_color);
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ TS->shaped_text_draw(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_color);
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines[i]) + spacing_bottom;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
}
}
}
@@ -556,11 +658,11 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
TS->shaped_text_draw_outline(dropcap_rid, p_canvas, dc_off + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_dc_color);
}
- for (int i = 0; i < lines.size(); i++) {
+ for (int i = 0; i < lines_rid.size(); i++) {
float l_width = width;
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
if (i <= dropcap_lines) {
if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -569,7 +671,7 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
}
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]) + spacing_top;
if (i <= dropcap_lines) {
if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
ofs.x -= h_offset;
@@ -577,21 +679,29 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
l_width -= h_offset;
}
}
- float length = TS->shaped_text_get_width(lines[i]);
+ float length = TS->shaped_text_get_width(lines_rid[i]);
if (width > 0) {
switch (align) {
case HALIGN_FILL:
+ if (TS->shaped_text_get_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ break;
case HALIGN_LEFT:
break;
case HALIGN_CENTER: {
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x += Math::floor((l_width - length) / 2.0);
} else {
ofs.y += Math::floor((l_width - length) / 2.0);
}
} break;
case HALIGN_RIGHT: {
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x += l_width - length;
} else {
ofs.y += l_width - length;
@@ -600,18 +710,18 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
}
}
float clip_l;
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
clip_l = MAX(0, p_pos.x - ofs.x);
} else {
clip_l = MAX(0, p_pos.y - ofs.y);
}
- TS->shaped_text_draw_outline(lines[i], p_canvas, ofs, clip_l, clip_l + l_width, p_outline_size, p_color);
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ TS->shaped_text_draw_outline(lines_rid[i], p_canvas, ofs, clip_l, clip_l + l_width, p_outline_size, p_color);
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
ofs.x = p_pos.x;
- ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
} else {
ofs.y = p_pos.y;
- ofs.x += TS->shaped_text_get_descent(lines[i]) + spacing_bottom;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]) + spacing_bottom;
}
}
}
@@ -628,17 +738,17 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
return 0;
}
}
- for (int i = 0; i < lines.size(); i++) {
- if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines[i]).y)) {
- return TS->shaped_text_hit_test_position(lines[i], p_coords.x);
+ for (int i = 0; i < lines_rid.size(); i++) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines_rid[i]).y)) {
+ return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.x);
}
- ofs.y += TS->shaped_text_get_size(lines[i]).y + spacing_bottom + spacing_top;
+ ofs.y += TS->shaped_text_get_size(lines_rid[i]).y + spacing_bottom + spacing_top;
} else {
- if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(lines[i]).x)) {
- return TS->shaped_text_hit_test_position(lines[i], p_coords.y);
+ if ((p_coords.x >= ofs.x) && (p_coords.x <= ofs.x + TS->shaped_text_get_size(lines_rid[i]).x)) {
+ return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.y);
}
- ofs.y += TS->shaped_text_get_size(lines[i]).x + spacing_bottom + spacing_top;
+ ofs.y += TS->shaped_text_get_size(lines_rid[i]).x + spacing_bottom + spacing_top;
}
}
return TS->shaped_text_get_range(rid).y;
@@ -690,29 +800,29 @@ void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int
void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND(p_line < 0 || p_line >= lines.size());
+ ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
Vector2 ofs = p_pos;
- if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
+ if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
} else {
- ofs.x += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
}
- return TS->shaped_text_draw(lines[p_line], p_canvas, ofs, -1, -1, p_color);
+ return TS->shaped_text_draw(lines_rid[p_line], p_canvas, ofs, -1, -1, p_color);
}
void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_line, int p_outline_size, const Color &p_color) const {
const_cast<TextParagraph *>(this)->_shape_lines();
- ERR_FAIL_COND(p_line < 0 || p_line >= lines.size());
+ ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
Vector2 ofs = p_pos;
- if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.y += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
+ if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
} else {
- ofs.x += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
}
- return TS->shaped_text_draw_outline(lines[p_line], p_canvas, ofs, -1, -1, p_outline_size, p_color);
+ return TS->shaped_text_draw_outline(lines_rid[p_line], p_canvas, ofs, -1, -1, p_outline_size, p_color);
}
TextParagraph::TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, float p_width, TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
@@ -729,10 +839,10 @@ TextParagraph::TextParagraph() {
}
TextParagraph::~TextParagraph() {
- for (int i = 0; i < lines.size(); i++) {
- TS->free(lines[i]);
+ for (int i = 0; i < lines_rid.size(); i++) {
+ TS->free(lines_rid[i]);
}
- lines.clear();
+ lines_rid.clear();
TS->free(rid);
TS->free(dropcap_rid);
}
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index d0747a9e03..ee7bbab9c5 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -39,19 +39,33 @@
class TextParagraph : public RefCounted {
GDCLASS(TextParagraph, RefCounted);
+public:
+ enum OverrunBehavior {
+ OVERRUN_NO_TRIMMING,
+ OVERRUN_TRIM_CHAR,
+ OVERRUN_TRIM_WORD,
+ OVERRUN_TRIM_ELLIPSIS,
+ OVERRUN_TRIM_WORD_ELLIPSIS,
+ };
+
+private:
RID dropcap_rid;
int dropcap_lines = 0;
Rect2 dropcap_margins;
RID rid;
- Vector<RID> lines;
+ Vector<RID> lines_rid;
int spacing_top = 0;
int spacing_bottom = 0;
- bool dirty_lines = true;
+ bool lines_dirty = true;
float width = -1.0;
+ int max_lines_visible = -1;
+
uint8_t flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
+ OverrunBehavior overrun_behavior = OVERRUN_NO_TRIMMING;
+
HAlign align = HALIGN_LEFT;
Vector<float> tab_stops;
@@ -97,9 +111,15 @@ public:
void set_flags(uint8_t p_flags);
uint8_t get_flags() const;
+ void set_text_overrun_behavior(OverrunBehavior p_behavior);
+ OverrunBehavior get_text_overrun_behavior() const;
+
void set_width(float p_width);
float get_width() const;
+ void set_max_lines_visible(int p_lines);
+ int get_max_lines_visible() const;
+
Size2 get_non_wraped_size() const;
Size2 get_size() const;
@@ -140,4 +160,6 @@ public:
~TextParagraph();
};
+VARIANT_ENUM_CAST(TextParagraph::OverrunBehavior);
+
#endif // TEXT_PARAGRAPH_H
diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp
index 29242a554b..5b75d1044a 100644
--- a/servers/physics_2d/collision_solver_2d_sat.cpp
+++ b/servers/physics_2d/collision_solver_2d_sat.cpp
@@ -1098,13 +1098,11 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
PhysicsServer2D::ShapeType type_A = p_shape_A->get_type();
ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_LINE, false);
- //ERR_FAIL_COND_V(type_A==PhysicsServer2D::SHAPE_RAY,false);
ERR_FAIL_COND_V(p_shape_A->is_concave(), false);
PhysicsServer2D::ShapeType type_B = p_shape_B->get_type();
ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_LINE, false);
- //ERR_FAIL_COND_V(type_B==PhysicsServer2D::SHAPE_RAY,false);
ERR_FAIL_COND_V(p_shape_B->is_concave(), false);
static const CollisionFunc collision_table[5][5] = {
@@ -1367,23 +1365,23 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D
if (p_margin_A || p_margin_B) {
if (*motion_A == Vector2() && *motion_B == Vector2()) {
- collision_func = collision_table_margin[type_A - 2][type_B - 2];
+ collision_func = collision_table_margin[type_A - 1][type_B - 1];
} else if (*motion_A != Vector2() && *motion_B == Vector2()) {
- collision_func = collision_table_castA_margin[type_A - 2][type_B - 2];
+ collision_func = collision_table_castA_margin[type_A - 1][type_B - 1];
} else if (*motion_A == Vector2() && *motion_B != Vector2()) {
- collision_func = collision_table_castB_margin[type_A - 2][type_B - 2];
+ collision_func = collision_table_castB_margin[type_A - 1][type_B - 1];
} else {
- collision_func = collision_table_castA_castB_margin[type_A - 2][type_B - 2];
+ collision_func = collision_table_castA_castB_margin[type_A - 1][type_B - 1];
}
} else {
if (*motion_A == Vector2() && *motion_B == Vector2()) {
- collision_func = collision_table[type_A - 2][type_B - 2];
+ collision_func = collision_table[type_A - 1][type_B - 1];
} else if (*motion_A != Vector2() && *motion_B == Vector2()) {
- collision_func = collision_table_castA[type_A - 2][type_B - 2];
+ collision_func = collision_table_castA[type_A - 1][type_B - 1];
} else if (*motion_A == Vector2() && *motion_B != Vector2()) {
- collision_func = collision_table_castB[type_A - 2][type_B - 2];
+ collision_func = collision_table_castB[type_A - 1][type_B - 1];
} else {
- collision_func = collision_table_castA_castB[type_A - 2][type_B - 2];
+ collision_func = collision_table_castA_castB[type_A - 1][type_B - 1];
}
}
diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp
index 5bd4d498c6..ed398a24e5 100644
--- a/servers/physics_2d/collision_solver_2d_sw.cpp
+++ b/servers/physics_2d/collision_solver_2d_sw.cpp
@@ -73,49 +73,6 @@ bool CollisionSolver2DSW::solve_static_line(const Shape2DSW *p_shape_A, const Tr
return found;
}
-bool CollisionSolver2DSW::solve_raycast(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis) {
- const RayShape2DSW *ray = static_cast<const RayShape2DSW *>(p_shape_A);
- if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_RAY) {
- return false;
- }
-
- Vector2 from = p_transform_A.get_origin();
- Vector2 to = from + p_transform_A[1] * ray->get_length();
- if (p_motion_A != Vector2()) {
- //not the best but should be enough
- Vector2 normal = (to - from).normalized();
- to += normal * MAX(0.0, normal.dot(p_motion_A));
- }
- Vector2 support_A = to;
-
- Transform2D invb = p_transform_B.affine_inverse();
- from = invb.xform(from);
- to = invb.xform(to);
-
- Vector2 p, n;
- if (!p_shape_B->intersect_segment(from, to, p, n)) {
- if (sep_axis) {
- *sep_axis = p_transform_A[1].normalized();
- }
- return false;
- }
-
- Vector2 support_B = p_transform_B.xform(p);
- if (ray->get_slips_on_slope()) {
- Vector2 global_n = invb.basis_xform_inv(n).normalized();
- support_B = support_A + (support_B - support_A).length() * global_n;
- }
-
- if (p_result_callback) {
- if (p_swap_result) {
- p_result_callback(support_B, support_A, p_userdata);
- } else {
- p_result_callback(support_A, support_B, p_userdata);
- }
- }
- return true;
-}
-
struct _ConcaveCollisionInfo2D {
const Transform2D *transform_A;
const Shape2DSW *shape_A;
@@ -210,7 +167,7 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p
}
if (type_A == PhysicsServer2D::SHAPE_LINE) {
- if (type_B == PhysicsServer2D::SHAPE_LINE || type_B == PhysicsServer2D::SHAPE_RAY) {
+ if (type_B == PhysicsServer2D::SHAPE_LINE) {
return false;
}
@@ -220,17 +177,6 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p
return solve_static_line(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
- } else if (type_A == PhysicsServer2D::SHAPE_RAY) {
- if (type_B == PhysicsServer2D::SHAPE_RAY) {
- return false; //no ray-ray
- }
-
- if (swap) {
- return solve_raycast(p_shape_B, p_motion_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, sep_axis);
- } else {
- return solve_raycast(p_shape_A, p_motion_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, sep_axis);
- }
-
} else if (concave_B) {
if (concave_A) {
return false;
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
index 467c664302..4dcc4a9cfd 100644
--- a/servers/physics_2d/physics_server_2d_sw.cpp
+++ b/servers/physics_2d/physics_server_2d_sw.cpp
@@ -45,9 +45,6 @@ RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) {
case SHAPE_LINE: {
shape = memnew(LineShape2DSW);
} break;
- case SHAPE_RAY: {
- shape = memnew(RayShape2DSW);
- } break;
case SHAPE_SEGMENT: {
shape = memnew(SegmentShape2DSW);
} break;
@@ -82,10 +79,6 @@ RID PhysicsServer2DSW::line_shape_create() {
return _shape_create(SHAPE_LINE);
}
-RID PhysicsServer2DSW::ray_shape_create() {
- return _shape_create(SHAPE_RAY);
-}
-
RID PhysicsServer2DSW::segment_shape_create() {
return _shape_create(SHAPE_SEGMENT);
}
@@ -946,7 +939,7 @@ void PhysicsServer2DSW::body_set_pickable(RID p_body, bool p_pickable) {
body->set_pickable(p_pickable);
}
-bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
+bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, MotionResult *r_result, const Set<RID> &p_exclude) {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
@@ -954,16 +947,7 @@ bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from,
_update_shapes();
- return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude);
-}
-
-int PhysicsServer2DSW::body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
- Body2DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_COND_V(!body->get_space(), false);
- ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
-
- return body->get_space()->test_body_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result, p_exclude);
}
PhysicsDirectBodyState2D *PhysicsServer2DSW::body_get_direct_state(RID p_body) {
diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h
index f40b5a7c42..e1ad6a56ee 100644
--- a/servers/physics_2d/physics_server_2d_sw.h
+++ b/servers/physics_2d/physics_server_2d_sw.h
@@ -88,7 +88,6 @@ public:
};
virtual RID line_shape_create() override;
- virtual RID ray_shape_create() override;
virtual RID segment_shape_create() override;
virtual RID circle_shape_create() override;
virtual RID rectangle_shape_create() override;
@@ -247,8 +246,7 @@ public:
virtual void body_set_pickable(RID p_body, bool p_pickable) override;
- virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override;
- virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.08) override;
+ virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) override;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override;
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
index fb7235c031..7bc1096f93 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.h
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.h
@@ -80,7 +80,6 @@ public:
//FUNC1RID(shape,ShapeType); todo fix
FUNCRID(line_shape)
- FUNCRID(ray_shape)
FUNCRID(segment_shape)
FUNCRID(circle_shape)
FUNCRID(rectangle_shape)
@@ -253,14 +252,9 @@ public:
FUNC2(body_set_pickable, RID, bool);
- bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override {
+ bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
- return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude);
- }
-
- int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.08) override {
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
- return physics_2d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
+ return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_margin, r_result, p_exclude);
}
// this function only works on physics process, errors and returns null otherwise
diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp
index 6cc086b9b7..ee0923effd 100644
--- a/servers/physics_2d/shape_2d_sw.cpp
+++ b/servers/physics_2d/shape_2d_sw.cpp
@@ -143,46 +143,6 @@ Variant LineShape2DSW::get_data() const {
/*********************************************************/
/*********************************************************/
-void RayShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
- r_amount = 1;
-
- if (p_normal.y > 0) {
- *r_supports = Vector2(0, length);
- } else {
- *r_supports = Vector2();
- }
-}
-
-bool RayShape2DSW::contains_point(const Vector2 &p_point) const {
- return false;
-}
-
-bool RayShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
- return false; //rays can't be intersected
-}
-
-real_t RayShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
- return 0; //rays are mass-less
-}
-
-void RayShape2DSW::set_data(const Variant &p_data) {
- Dictionary d = p_data;
- length = d["length"];
- slips_on_slope = d["slips_on_slope"];
- configure(Rect2(0, 0, 0.001, length));
-}
-
-Variant RayShape2DSW::get_data() const {
- Dictionary d;
- d["length"] = length;
- d["slips_on_slope"] = slips_on_slope;
- return d;
-}
-
-/*********************************************************/
-/*********************************************************/
-/*********************************************************/
-
void SegmentShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
if (Math::abs(p_normal.dot(n)) > _SEGMENT_IS_VALID_SUPPORT_THRESHOLD) {
r_supports[0] = a;
diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h
index ee2730ebb5..be2eeb8ed3 100644
--- a/servers/physics_2d/shape_2d_sw.h
+++ b/servers/physics_2d/shape_2d_sw.h
@@ -189,41 +189,6 @@ public:
}
};
-class RayShape2DSW : public Shape2DSW {
- real_t length;
- bool slips_on_slope;
-
-public:
- _FORCE_INLINE_ real_t get_length() const { return length; }
- _FORCE_INLINE_ bool get_slips_on_slope() const { return slips_on_slope; }
-
- virtual PhysicsServer2D::ShapeType get_type() const { return PhysicsServer2D::SHAPE_RAY; }
-
- virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { project_range(p_normal, p_transform, r_min, r_max); }
- virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const;
-
- virtual bool contains_point(const Vector2 &p_point) const;
- virtual bool intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const;
- virtual real_t get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const;
-
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
-
- _FORCE_INLINE_ void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const {
- //real large
- r_max = p_normal.dot(p_transform.get_origin());
- r_min = p_normal.dot(p_transform.xform(Vector2(0, length)));
- if (r_max < r_min) {
- SWAP(r_max, r_min);
- }
- }
-
- DEFAULT_PROJECT_RANGE_CAST
-
- _FORCE_INLINE_ RayShape2DSW() {}
- _FORCE_INLINE_ RayShape2DSW(real_t p_length) { length = p_length; }
-};
-
class SegmentShape2DSW : public Shape2DSW {
Vector2 a;
Vector2 b;
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 590c93a7be..65dc198592 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -528,188 +528,7 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) {
return amount;
}
-int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, PhysicsServer2D::SeparationResult *r_results, int p_result_max, real_t p_margin) {
- Rect2 body_aabb;
-
- bool shapes_found = false;
-
- for (int i = 0; i < p_body->get_shape_count(); i++) {
- if (p_body->is_shape_disabled(i)) {
- continue;
- }
-
- if (p_body->get_shape(i)->get_type() != PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
- if (!shapes_found) {
- body_aabb = p_body->get_shape_aabb(i);
- shapes_found = true;
- } else {
- body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
- }
- }
-
- if (!shapes_found) {
- return 0;
- }
-
- // Undo the currently transform the physics server is aware of and apply the provided one
- body_aabb = p_transform.xform(p_body->get_inv_transform().xform(body_aabb));
- body_aabb = body_aabb.grow(p_margin);
-
- Transform2D body_transform = p_transform;
-
- for (int i = 0; i < p_result_max; i++) {
- //reset results
- r_results[i].collision_depth = 0;
- }
-
- int rays_found = 0;
-
- {
- // raycast AND separate
-
- const int max_results = 32;
- int recover_attempts = 4;
- Vector2 sr[max_results * 2];
- PhysicsServer2DSW::CollCbkData cbk;
- cbk.max = max_results;
- PhysicsServer2DSW::CollCbkData *cbkptr = &cbk;
- CollisionSolver2DSW::CallbackResult cbkres = PhysicsServer2DSW::_shape_col_cbk;
-
- do {
- Vector2 recover_motion;
-
- bool collided = false;
-
- int amount = _cull_aabb_for_body(p_body, body_aabb);
-
- for (int j = 0; j < p_body->get_shape_count(); j++) {
- if (p_body->is_shape_disabled(j)) {
- continue;
- }
-
- Shape2DSW *body_shape = p_body->get_shape(j);
-
- if (body_shape->get_type() != PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
- Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
-
- for (int i = 0; i < amount; i++) {
- const CollisionObject2DSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
-
- cbk.amount = 0;
- cbk.passed = 0;
- cbk.ptr = sr;
- cbk.invalid_by_dir = 0;
-
- if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
-
- Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
-
- /*
- * There is no point in supporting one way collisions with ray shapes, as they will always collide in the desired
- * direction. Use a short ray shape if you want to achieve a similar effect.
- *
- if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
- cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
- cbk.valid_depth = p_margin; //only valid depth is the collision margin
- cbk.invalid_by_dir = 0;
-
- } else {
-*/
-
- cbk.valid_dir = Vector2();
- cbk.valid_depth = 0;
- cbk.invalid_by_dir = 0;
-
- /*
- }
- */
-
- Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
- if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_margin)) {
- if (cbk.amount > 0) {
- collided = true;
- }
-
- int ray_index = -1; //reuse shape
- for (int k = 0; k < rays_found; k++) {
- if (r_results[ray_index].collision_local_shape == j) {
- ray_index = k;
- }
- }
-
- if (ray_index == -1 && rays_found < p_result_max) {
- ray_index = rays_found;
- rays_found++;
- }
-
- if (ray_index != -1) {
- PhysicsServer2D::SeparationResult &result = r_results[ray_index];
-
- for (int k = 0; k < cbk.amount; k++) {
- Vector2 a = sr[k * 2 + 0];
- Vector2 b = sr[k * 2 + 1];
-
- recover_motion += (b - a) / cbk.amount;
-
- real_t depth = a.distance_to(b);
- if (depth > result.collision_depth) {
- result.collision_depth = depth;
- result.collision_point = b;
- result.collision_normal = (b - a).normalized();
- result.collision_local_shape = j;
- result.collider_shape = shape_idx;
- result.collider = col_obj->get_self();
- result.collider_id = col_obj->get_instance_id();
- result.collider_metadata = col_obj->get_shape_metadata(shape_idx);
- if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
- Body2DSW *body = (Body2DSW *)col_obj;
-
- Vector2 rel_vec = b - body->get_transform().get_origin();
- result.collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
- }
- }
- }
- }
- }
- }
- }
-
- if (!collided || recover_motion == Vector2()) {
- break;
- }
-
- body_transform.elements[2] += recover_motion;
- body_aabb.position += recover_motion;
-
- recover_attempts--;
- } while (recover_attempts);
- }
-
- //optimize results (remove non colliding)
- for (int i = 0; i < rays_found; i++) {
- if (r_results[i].collision_depth == 0) {
- rays_found--;
- SWAP(r_results[i], r_results[rays_found]);
- }
- }
-
- r_recover_motion = body_transform.elements[2] - p_transform.elements[2];
- return rays_found;
-}
-
-bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
+bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, PhysicsServer2D::MotionResult *r_result, const Set<RID> &p_exclude) {
//give me back regular physics engine logic
//this is madness
//and most people using this function will think
@@ -730,10 +549,6 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
continue;
}
- if (p_exclude_raycast_shapes && p_body->get_shape(i)->get_type() == PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
if (!shapes_found) {
body_aabb = p_body->get_shape_aabb(i);
shapes_found = true;
@@ -794,24 +609,15 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
Shape2DSW *body_shape = p_body->get_shape(j);
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
+
for (int i = 0; i < amount; i++) {
const CollisionObject2DSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
- int shape_idx = intersection_query_subindex_results[i];
- if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
+ int shape_idx = intersection_query_subindex_results[i];
Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
@@ -920,10 +726,6 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
Shape2DSW *body_shape = p_body->get_shape(body_shape_idx);
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(body_shape_idx);
bool stuck = false;
@@ -939,13 +741,6 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
int col_shape_idx = intersection_query_subindex_results[i];
Shape2DSW *against_shape = col_obj->get_shape(col_shape_idx);
- if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
-
bool excluded = false;
for (int k = 0; k < excluded_shape_pair_count; k++) {
@@ -1082,10 +877,6 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j);
Shape2DSW *body_shape = p_body->get_shape(j);
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer2D::SHAPE_RAY) {
- continue;
- }
-
body_aabb.position += p_motion * unsafe;
int amount = _cull_aabb_for_body(p_body, body_aabb);
@@ -1095,14 +886,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (p_exclude.has(col_obj->get_self())) {
continue;
}
- int shape_idx = intersection_query_subindex_results[i];
- if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) {
- const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer2D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer2D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
+ int shape_idx = intersection_query_subindex_results[i];
Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h
index f7224e4661..3be36852b0 100644
--- a/servers/physics_2d/space_2d_sw.h
+++ b/servers/physics_2d/space_2d_sw.h
@@ -183,8 +183,7 @@ public:
int get_collision_pairs() const { return collision_pairs; }
- bool test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>());
- int test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, PhysicsServer2D::SeparationResult *r_results, int p_result_max, real_t p_margin);
+ bool test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, PhysicsServer2D::MotionResult *r_result, const Set<RID> &p_exclude = Set<RID>());
void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); }
_FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); }
diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp
index 852e9ecd74..e6a17b3a1a 100644
--- a/servers/physics_3d/collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/collision_solver_3d_sat.cpp
@@ -2273,13 +2273,11 @@ bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_
PhysicsServer3D::ShapeType type_A = p_shape_A->get_type();
ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_PLANE, false);
- ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_RAY, false);
ERR_FAIL_COND_V(p_shape_A->is_concave(), false);
PhysicsServer3D::ShapeType type_B = p_shape_B->get_type();
ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_PLANE, false);
- ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_RAY, false);
ERR_FAIL_COND_V(p_shape_B->is_concave(), false);
static const CollisionFunc collision_table[6][6] = {
@@ -2384,10 +2382,10 @@ bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_
CollisionFunc collision_func;
if (margin_A != 0.0 || margin_B != 0.0) {
- collision_func = collision_table_margin[type_A - 2][type_B - 2];
+ collision_func = collision_table_margin[type_A - 1][type_B - 1];
} else {
- collision_func = collision_table[type_A - 2][type_B - 2];
+ collision_func = collision_table[type_A - 1][type_B - 1];
}
ERR_FAIL_COND_V(!collision_func, false);
diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp
index 67330d497e..161e7e101b 100644
--- a/servers/physics_3d/collision_solver_3d_sw.cpp
+++ b/servers/physics_3d/collision_solver_3d_sw.cpp
@@ -89,39 +89,6 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T
return found;
}
-bool CollisionSolver3DSW::solve_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
- const RayShape3DSW *ray = static_cast<const RayShape3DSW *>(p_shape_A);
-
- Vector3 from = p_transform_A.origin;
- Vector3 to = from + p_transform_A.basis.get_axis(2) * ray->get_length();
- Vector3 support_A = to;
-
- Transform3D ai = p_transform_B.affine_inverse();
-
- from = ai.xform(from);
- to = ai.xform(to);
-
- Vector3 p, n;
- if (!p_shape_B->intersect_segment(from, to, p, n)) {
- return false;
- }
-
- Vector3 support_B = p_transform_B.xform(p);
- if (ray->get_slips_on_slope()) {
- Vector3 global_n = ai.basis.xform_inv(n).normalized();
- support_B = support_A + (support_B - support_A).length() * global_n;
- }
-
- if (p_result_callback) {
- if (p_swap_result) {
- p_result_callback(support_B, 0, support_A, 0, p_userdata);
- } else {
- p_result_callback(support_A, 0, support_B, 0, p_userdata);
- }
- }
- return true;
-}
-
struct _SoftBodyContactCollisionInfo {
int node_index = 0;
CollisionSolver3DSW::CallbackResult result_callback = nullptr;
@@ -347,9 +314,6 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
if (type_B == PhysicsServer3D::SHAPE_PLANE) {
return false;
}
- if (type_B == PhysicsServer3D::SHAPE_RAY) {
- return false;
- }
if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
return false;
}
@@ -360,17 +324,6 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo
return solve_static_plane(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
}
- } else if (type_A == PhysicsServer3D::SHAPE_RAY) {
- if (type_B == PhysicsServer3D::SHAPE_RAY) {
- return false;
- }
-
- if (swap) {
- return solve_ray(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
- } else {
- return solve_ray(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
- }
-
} else if (type_B == PhysicsServer3D::SHAPE_SOFT_BODY) {
if (type_A == PhysicsServer3D::SHAPE_SOFT_BODY) {
// Soft Body / Soft Body not supported.
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index e2ab84428b..fbb374bd74 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -48,12 +48,6 @@ RID PhysicsServer3DSW::plane_shape_create() {
shape->set_self(rid);
return rid;
}
-RID PhysicsServer3DSW::ray_shape_create() {
- Shape3DSW *shape = memnew(RayShape3DSW);
- RID rid = shape_owner.make_rid(shape);
- shape->set_self(rid);
- return rid;
-}
RID PhysicsServer3DSW::sphere_shape_create() {
Shape3DSW *shape = memnew(SphereShape3DSW);
RID rid = shape_owner.make_rid(shape);
@@ -854,18 +848,7 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
body->set_ray_pickable(p_enable);
}
-bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
- Body3DSW *body = body_owner.getornull(p_body);
- ERR_FAIL_COND_V(!body, false);
- ERR_FAIL_COND_V(!body->get_space(), false);
- ERR_FAIL_COND_V(body->get_space()->is_locked(), false);
-
- _update_shapes();
-
- return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude);
-}
-
-int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
+bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, MotionResult *r_result, const Set<RID> &p_exclude) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
@@ -873,7 +856,7 @@ int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform3D &p
_update_shapes();
- return body->get_space()->test_body_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result, p_exclude);
}
PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) {
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index 326b6fbe7a..6e59a77e89 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -83,7 +83,6 @@ public:
static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
virtual RID plane_shape_create() override;
- virtual RID ray_shape_create() override;
virtual RID sphere_shape_create() override;
virtual RID box_shape_create() override;
virtual RID capsule_shape_create() override;
@@ -242,8 +241,7 @@ public:
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
- virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override;
- virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) override;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h
index c3c2e50e56..75174628bf 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.h
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -79,7 +79,6 @@ public:
//FUNC1RID(shape,ShapeType); todo fix
FUNCRID(plane_shape)
- FUNCRID(ray_shape)
FUNCRID(sphere_shape)
FUNCRID(box_shape)
FUNCRID(capsule_shape)
@@ -250,14 +249,9 @@ public:
FUNC2(body_set_ray_pickable, RID, bool);
- bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override {
+ bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
- return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude);
- }
-
- int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override {
- ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
- return physics_3d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
+ return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_margin, r_result, p_exclude);
}
// this function only works on physics process, errors and returns null otherwise
diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp
index 5b3721861e..526a098a05 100644
--- a/servers/physics_3d/shape_3d_sw.cpp
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -164,91 +164,6 @@ Variant PlaneShape3DSW::get_data() const {
PlaneShape3DSW::PlaneShape3DSW() {
}
-//
-
-real_t RayShape3DSW::get_length() const {
- return length;
-}
-
-bool RayShape3DSW::get_slips_on_slope() const {
- return slips_on_slope;
-}
-
-void RayShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
- // don't think this will be even used
- r_min = 0;
- r_max = 1;
-}
-
-Vector3 RayShape3DSW::get_support(const Vector3 &p_normal) const {
- if (p_normal.z > 0) {
- return Vector3(0, 0, length);
- } else {
- return Vector3(0, 0, 0);
- }
-}
-
-void RayShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
- if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) {
- r_amount = 2;
- r_type = FEATURE_EDGE;
- r_supports[0] = Vector3(0, 0, 0);
- r_supports[1] = Vector3(0, 0, length);
- } else if (p_normal.z > 0) {
- r_amount = 1;
- r_type = FEATURE_POINT;
- *r_supports = Vector3(0, 0, length);
- } else {
- r_amount = 1;
- r_type = FEATURE_POINT;
- *r_supports = Vector3(0, 0, 0);
- }
-}
-
-bool RayShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const {
- return false; //simply not possible
-}
-
-bool RayShape3DSW::intersect_point(const Vector3 &p_point) const {
- return false; //simply not possible
-}
-
-Vector3 RayShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
- Vector3 s[2] = {
- Vector3(0, 0, 0),
- Vector3(0, 0, length)
- };
-
- return Geometry3D::get_closest_point_to_segment(p_point, s);
-}
-
-Vector3 RayShape3DSW::get_moment_of_inertia(real_t p_mass) const {
- return Vector3();
-}
-
-void RayShape3DSW::_setup(real_t p_length, bool p_slips_on_slope) {
- length = p_length;
- slips_on_slope = p_slips_on_slope;
- configure(AABB(Vector3(0, 0, 0), Vector3(0.1, 0.1, length)));
-}
-
-void RayShape3DSW::set_data(const Variant &p_data) {
- Dictionary d = p_data;
- _setup(d["length"], d["slips_on_slope"]);
-}
-
-Variant RayShape3DSW::get_data() const {
- Dictionary d;
- d["length"] = length;
- d["slips_on_slope"] = slips_on_slope;
- return d;
-}
-
-RayShape3DSW::RayShape3DSW() {
- length = 1;
- slips_on_slope = false;
-}
-
/********** SPHERE *************/
real_t SphereShape3DSW::get_radius() const {
diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h
index 72be34b788..dde423ad60 100644
--- a/servers/physics_3d/shape_3d_sw.h
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -145,34 +145,6 @@ public:
PlaneShape3DSW();
};
-class RayShape3DSW : public Shape3DSW {
- real_t length;
- bool slips_on_slope;
-
- void _setup(real_t p_length, bool p_slips_on_slope);
-
-public:
- real_t get_length() const;
- bool get_slips_on_slope() const;
-
- virtual real_t get_area() const { return 0.0; }
- virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_RAY; }
- virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
- virtual Vector3 get_support(const Vector3 &p_normal) const;
- virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const;
-
- virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const;
- virtual bool intersect_point(const Vector3 &p_point) const;
- virtual Vector3 get_closest_point_to(const Vector3 &p_point) const;
-
- virtual Vector3 get_moment_of_inertia(real_t p_mass) const;
-
- virtual void set_data(const Variant &p_data);
- virtual Variant get_data() const;
-
- RayShape3DSW();
-};
-
class SphereShape3DSW : public Shape3DSW {
real_t radius;
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index 2a39a9d363..730460d66a 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -569,158 +569,7 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
return amount;
}
-int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) {
- AABB body_aabb;
-
- bool shapes_found = false;
-
- for (int i = 0; i < p_body->get_shape_count(); i++) {
- if (p_body->is_shape_disabled(i)) {
- continue;
- }
-
- if (!shapes_found) {
- body_aabb = p_body->get_shape_aabb(i);
- shapes_found = true;
- } else {
- body_aabb = body_aabb.merge(p_body->get_shape_aabb(i));
- }
- }
-
- if (!shapes_found) {
- return 0;
- }
- // Undo the currently transform the physics server is aware of and apply the provided one
- body_aabb = p_transform.xform(p_body->get_inv_transform().xform(body_aabb));
- body_aabb = body_aabb.grow(p_margin);
-
- Transform3D body_transform = p_transform;
-
- for (int i = 0; i < p_result_max; i++) {
- //reset results
- r_results[i].collision_depth = 0;
- }
-
- int rays_found = 0;
-
- {
- // raycast AND separate
-
- const int max_results = 32;
- int recover_attempts = 4;
- Vector3 sr[max_results * 2];
- PhysicsServer3DSW::CollCbkData cbk;
- cbk.max = max_results;
- PhysicsServer3DSW::CollCbkData *cbkptr = &cbk;
- CollisionSolver3DSW::CallbackResult cbkres = PhysicsServer3DSW::_shape_col_cbk;
-
- do {
- Vector3 recover_motion;
-
- bool collided = false;
-
- int amount = _cull_aabb_for_body(p_body, body_aabb);
-
- for (int j = 0; j < p_body->get_shape_count(); j++) {
- if (p_body->is_shape_disabled(j)) {
- continue;
- }
-
- Shape3DSW *body_shape = p_body->get_shape(j);
-
- if (body_shape->get_type() != PhysicsServer3D::SHAPE_RAY) {
- continue;
- }
-
- Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j);
-
- for (int i = 0; i < amount; i++) {
- const CollisionObject3DSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
-
- cbk.amount = 0;
- cbk.ptr = sr;
-
- if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
- const Body3DSW *b = static_cast<const Body3DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer3D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer3D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
-
- Shape3DSW *against_shape = col_obj->get_shape(shape_idx);
- if (CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) {
- if (cbk.amount > 0) {
- collided = true;
- }
-
- int ray_index = -1; //reuse shape
- for (int k = 0; k < rays_found; k++) {
- if (r_results[k].collision_local_shape == j) {
- ray_index = k;
- }
- }
-
- if (ray_index == -1 && rays_found < p_result_max) {
- ray_index = rays_found;
- rays_found++;
- }
-
- if (ray_index != -1) {
- PhysicsServer3D::SeparationResult &result = r_results[ray_index];
-
- for (int k = 0; k < cbk.amount; k++) {
- Vector3 a = sr[k * 2 + 0];
- Vector3 b = sr[k * 2 + 1];
-
- recover_motion += (b - a) / cbk.amount;
-
- real_t depth = a.distance_to(b);
- if (depth > result.collision_depth) {
- result.collision_depth = depth;
- result.collision_point = b;
- result.collision_normal = (b - a).normalized();
- result.collision_local_shape = j;
- result.collider = col_obj->get_self();
- result.collider_id = col_obj->get_instance_id();
- result.collider_shape = shape_idx;
- //result.collider_metadata = col_obj->get_shape_metadata(shape_idx);
- if (col_obj->get_type() == CollisionObject3DSW::TYPE_BODY) {
- Body3DSW *body = (Body3DSW *)col_obj;
- Vector3 rel_vec = b - (body->get_transform().origin + body->get_center_of_mass());
- result.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
- }
- }
- }
- }
- }
- }
- }
-
- if (!collided || recover_motion == Vector3()) {
- break;
- }
-
- body_transform.origin += recover_motion;
- body_aabb.position += recover_motion;
-
- recover_attempts--;
- } while (recover_attempts);
- }
-
- //optimize results (remove non colliding)
- for (int i = 0; i < rays_found; i++) {
- if (r_results[i].collision_depth == 0) {
- rays_found--;
- SWAP(r_results[i], r_results[rays_found]);
- }
- }
-
- r_recover_motion = body_transform.origin - p_transform.origin;
- return rays_found;
-}
-
-bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
+bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, const Set<RID> &p_exclude) {
//give me back regular physics engine logic
//this is madness
//and most people using this function will think
@@ -795,23 +644,14 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j);
Shape3DSW *body_shape = p_body->get_shape(j);
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) {
- continue;
- }
for (int i = 0; i < amount; i++) {
const CollisionObject3DSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
- int shape_idx = intersection_query_subindex_results[i];
- if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
- const Body3DSW *b = static_cast<const Body3DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer3D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer3D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
+ int shape_idx = intersection_query_subindex_results[i];
if (CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) {
collided = cbk.amount > 0;
@@ -877,10 +717,6 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j);
Shape3DSW *body_shape = p_body->get_shape(j);
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) {
- continue;
- }
-
Transform3D body_shape_xform_inv = body_shape_xform.affine_inverse();
MotionShape3DSW mshape;
mshape.shape = body_shape;
@@ -896,14 +732,8 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
if (p_exclude.has(col_obj->get_self())) {
continue;
}
- int shape_idx = intersection_query_subindex_results[i];
- if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
- const Body3DSW *b = static_cast<const Body3DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer3D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer3D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
+ int shape_idx = intersection_query_subindex_results[i];
//test initial overlap, does it collide if going all the way?
Vector3 point_A, point_B;
@@ -1011,10 +841,6 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
Transform3D body_shape_xform = ugt * p_body->get_shape_transform(j);
Shape3DSW *body_shape = p_body->get_shape(j);
- if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) {
- continue;
- }
-
body_aabb.position += p_motion * unsafe;
int amount = _cull_aabb_for_body(p_body, body_aabb);
@@ -1026,13 +852,6 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
}
int shape_idx = intersection_query_subindex_results[i];
- if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
- const Body3DSW *b = static_cast<const Body3DSW *>(col_obj);
- if (p_infinite_inertia && PhysicsServer3D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer3D::BODY_MODE_KINEMATIC != b->get_mode()) {
- continue;
- }
- }
-
rcd.object = col_obj;
rcd.shape = shape_idx;
bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin);
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
index 580693deba..9b5b4de069 100644
--- a/servers/physics_3d/space_3d_sw.h
+++ b/servers/physics_3d/space_3d_sw.h
@@ -203,8 +203,7 @@ public:
void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; }
uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
- int test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin);
- bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>());
+ bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, const Set<RID> &p_exclude = Set<RID>());
Space3DSW();
~Space3DSW();
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index 2e44a1a10b..3efa16fe0a 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -500,7 +500,7 @@ void PhysicsTestMotionResult2D::_bind_methods() {
///////////////////////////////////////
-bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult2D> &p_result, bool p_exclude_raycast_shapes, const Vector<RID> &p_exclude) {
+bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, const Ref<PhysicsTestMotionResult2D> &p_result, const Vector<RID> &p_exclude) {
MotionResult *r = nullptr;
if (p_result.is_valid()) {
r = p_result->get_result_ptr();
@@ -509,12 +509,11 @@ bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, c
for (int i = 0; i < p_exclude.size(); i++) {
exclude.insert(p_exclude[i]);
}
- return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes, exclude);
+ return body_test_motion(p_body, p_from, p_motion, p_margin, r, exclude);
}
void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("line_shape_create"), &PhysicsServer2D::line_shape_create);
- ClassDB::bind_method(D_METHOD("ray_shape_create"), &PhysicsServer2D::ray_shape_create);
ClassDB::bind_method(D_METHOD("segment_shape_create"), &PhysicsServer2D::segment_shape_create);
ClassDB::bind_method(D_METHOD("circle_shape_create"), &PhysicsServer2D::circle_shape_create);
ClassDB::bind_method(D_METHOD("rectangle_shape_create"), &PhysicsServer2D::rectangle_shape_create);
@@ -636,7 +635,7 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant()));
- ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result", "exclude_raycast_shapes", "exclude"), &PhysicsServer2D::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant()), DEFVAL(true), DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "margin", "result", "exclude"), &PhysicsServer2D::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant()), DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer2D::body_get_direct_state);
@@ -676,7 +675,6 @@ void PhysicsServer2D::_bind_methods() {
BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH);
BIND_ENUM_CONSTANT(SHAPE_LINE);
- BIND_ENUM_CONSTANT(SHAPE_RAY);
BIND_ENUM_CONSTANT(SHAPE_SEGMENT);
BIND_ENUM_CONSTANT(SHAPE_CIRCLE);
BIND_ENUM_CONSTANT(SHAPE_RECTANGLE);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index fafde62599..dbbc128793 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -210,7 +210,7 @@ class PhysicsServer2D : public Object {
static PhysicsServer2D *singleton;
- virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>(), bool p_exclude_raycast_shapes = true, const Vector<RID> &p_exclude = Vector<RID>());
+ virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>(), const Vector<RID> &p_exclude = Vector<RID>());
protected:
static void _bind_methods();
@@ -220,7 +220,6 @@ public:
enum ShapeType {
SHAPE_LINE, ///< plane:"plane"
- SHAPE_RAY, ///< float:"length"
SHAPE_SEGMENT, ///< float:"length"
SHAPE_CIRCLE, ///< float:"radius"
SHAPE_RECTANGLE, ///< vec3:"extents"
@@ -231,7 +230,6 @@ public:
};
virtual RID line_shape_create() = 0;
- virtual RID ray_shape_create() = 0;
virtual RID segment_shape_create() = 0;
virtual RID circle_shape_create() = 0;
virtual RID rectangle_shape_create() = 0;
@@ -483,7 +481,7 @@ public:
Variant collider_metadata;
};
- virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) = 0;
+ virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) = 0;
struct SeparationResult {
real_t collision_depth;
@@ -497,8 +495,6 @@ public:
Variant collider_metadata;
};
- virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.08) = 0;
-
/* JOINT API */
virtual RID joint_create() = 0;
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index b4ee5fbaf0..89987b5fe9 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -447,7 +447,7 @@ void PhysicsTestMotionResult3D::_bind_methods() {
///////////////////////////////////////
-bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result, bool p_exclude_raycast_shapes, const Vector<RID> &p_exclude) {
+bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result, const Vector<RID> &p_exclude) {
MotionResult *r = nullptr;
if (p_result.is_valid()) {
r = p_result->get_result_ptr();
@@ -456,15 +456,13 @@ bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, c
for (int i = 0; i < p_exclude.size(); i++) {
exclude.insert(p_exclude[i]);
}
- return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes, exclude);
+ return body_test_motion(p_body, p_from, p_motion, p_margin, r, exclude);
}
RID PhysicsServer3D::shape_create(ShapeType p_shape) {
switch (p_shape) {
case SHAPE_PLANE:
return plane_shape_create();
- case SHAPE_RAY:
- return ray_shape_create();
case SHAPE_SPHERE:
return sphere_shape_create();
case SHAPE_BOX:
@@ -490,7 +488,6 @@ void PhysicsServer3D::_bind_methods() {
#ifndef _3D_DISABLED
ClassDB::bind_method(D_METHOD("plane_shape_create"), &PhysicsServer3D::plane_shape_create);
- ClassDB::bind_method(D_METHOD("ray_shape_create"), &PhysicsServer3D::ray_shape_create);
ClassDB::bind_method(D_METHOD("sphere_shape_create"), &PhysicsServer3D::sphere_shape_create);
ClassDB::bind_method(D_METHOD("box_shape_create"), &PhysicsServer3D::box_shape_create);
ClassDB::bind_method(D_METHOD("capsule_shape_create"), &PhysicsServer3D::capsule_shape_create);
@@ -612,7 +609,7 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable);
- ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result", "exclude_raycast_shapes", "exclude"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()), DEFVAL(true), DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "margin", "result", "exclude"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()), DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state);
@@ -751,7 +748,6 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &PhysicsServer3D::get_process_info);
BIND_ENUM_CONSTANT(SHAPE_PLANE);
- BIND_ENUM_CONSTANT(SHAPE_RAY);
BIND_ENUM_CONSTANT(SHAPE_SPHERE);
BIND_ENUM_CONSTANT(SHAPE_BOX);
BIND_ENUM_CONSTANT(SHAPE_CAPSULE);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 0d3d5bd4a1..31ae352d9e 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -212,7 +212,7 @@ class PhysicsServer3D : public Object {
static PhysicsServer3D *singleton;
- virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>(), bool p_exclude_raycast_shapes = true, const Vector<RID> &p_exclude = Vector<RID>());
+ virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>(), const Vector<RID> &p_exclude = Vector<RID>());
protected:
static void _bind_methods();
@@ -222,7 +222,6 @@ public:
enum ShapeType {
SHAPE_PLANE, ///< plane:"plane"
- SHAPE_RAY, ///< float:"length"
SHAPE_SPHERE, ///< float:"radius"
SHAPE_BOX, ///< vec3:"extents"
SHAPE_CAPSULE, ///< dict( float:"radius", float:"height"):capsule
@@ -237,7 +236,6 @@ public:
RID shape_create(ShapeType p_shape);
virtual RID plane_shape_create() = 0;
- virtual RID ray_shape_create() = 0;
virtual RID sphere_shape_create() = 0;
virtual RID box_shape_create() = 0;
virtual RID capsule_shape_create() = 0;
@@ -491,21 +489,7 @@ public:
Variant collider_metadata;
};
- virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) = 0;
-
- struct SeparationResult {
- real_t collision_depth;
- Vector3 collision_point;
- Vector3 collision_normal;
- Vector3 collider_velocity;
- int collision_local_shape;
- ObjectID collider_id;
- RID collider;
- int collider_shape;
- Variant collider_metadata;
- };
-
- virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) = 0;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, const Set<RID> &p_exclude = Set<RID>()) = 0;
/* SOFT BODY */
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index c4fbf3b19d..5920444f7a 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -211,7 +211,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
float blinn = pow(cNdotH, shininess);
blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI));
- specular_light += light_color * attenuation * specular_amount * blinn * albedo * unpackUnorm4x8(orms).w;
+ specular_light += light_color * attenuation * specular_amount * blinn * f0 * unpackUnorm4x8(orms).w;
#elif defined(SPECULAR_PHONG)
@@ -221,7 +221,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
float phong = pow(cRdotV, shininess);
phong *= (shininess + 1.0) * (1.0 / (8.0 * M_PI));
- specular_light += light_color * attenuation * specular_amount * phong * albedo * unpackUnorm4x8(orms).w;
+ specular_light += light_color * attenuation * specular_amount * phong * f0 * unpackUnorm4x8(orms).w;
#elif defined(SPECULAR_TOON)
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index baa5381554..8e1d4ffdd5 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -4252,9 +4252,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (ident_type == IDENTIFIER_VARYING) {
TkPos prev_pos = _get_tkpos();
Token next_token = _get_token();
+
+ // An array of varyings.
+ if (next_token.type == TK_BRACKET_OPEN) {
+ _get_token(); // Pass constant.
+ _get_token(); // Pass TK_BRACKET_CLOSE.
+ next_token = _get_token();
+ }
_set_tkpos(prev_pos);
- String error;
+ String error;
if (is_token_operator_assign(next_token.type)) {
if (!_validate_varying_assign(shader->varyings[identifier], &error)) {
_set_error(error);
@@ -6860,6 +6867,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
DataInterpolation interpolation = INTERPOLATION_SMOOTH;
DataType type;
StringName name;
+ int array_size = 0;
tk = _get_token();
if (is_token_interpolation(tk.type)) {
@@ -6890,6 +6898,30 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
tk = _get_token();
+
+ if (tk.type == TK_BRACKET_OPEN) {
+ if (uniform) {
+ _set_error(vformat("Uniform arrays are not yet implemented!"));
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
+
+ if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
+ array_size = (int)tk.constant;
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
+ tk = _get_token();
+ } else {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier!");
return ERR_PARSE_ERROR;
@@ -7189,6 +7221,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
varying.precision = precision;
varying.interpolation = interpolation;
varying.tkpos = name_pos;
+ varying.array_size = array_size;
tk = _get_token();
if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) {
@@ -7197,6 +7230,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
if (tk.type == TK_BRACKET_OPEN) {
+ if (array_size > 0) {
+ _set_error("Array size is already defined!");
+ return ERR_PARSE_ERROR;
+ }
tk = _get_token();
if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
varying.array_size = (int)tk.constant;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index e32ea9cdea..6bace8cf9e 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -739,6 +739,11 @@ Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped, int p_gra
return words;
}
+TextServer::TrimData TextServer::shaped_text_get_trim_data(RID p_shaped) const {
+ WARN_PRINT("Getting overrun data not supported by this TextServer.");
+ return TrimData();
+}
+
void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const {
Vector<Rect2> carets;
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
@@ -976,7 +981,7 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start,
ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - start), off + advance));
}
}
- // Selection range is within grapheme
+ // Selection range is within grapheme.
if (glyphs[i].start < start && glyphs[i].end > end) {
float advance = 0.f;
for (int j = 0; j < glyphs[i].count; j++) {
@@ -1137,10 +1142,26 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped);
+ bool rtl = shaped_text_get_direction(p_shaped) == DIRECTION_RTL;
+ TrimData trim_data = shaped_text_get_trim_data(p_shaped);
+
int v_size = visual.size();
const Glyph *glyphs = visual.ptr();
Vector2 ofs = p_pos;
+ // Draw RTL ellipsis string when needed.
+ if (rtl && trim_data.ellipsis_pos >= 0) {
+ for (int i = trim_data.ellipsis_glyph_buf.size() - 1; i >= 0; i--) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
+ font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+ } else {
+ ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+ }
+ }
+ }
+ }
// Draw at the baseline.
for (int i = 0; i < v_size; i++) {
for (int j = 0; j < glyphs[i].repeat; j++) {
@@ -1170,6 +1191,18 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
}
}
}
+ if (trim_data.trim_pos >= 0) {
+ if (rtl) {
+ if (i < trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ continue;
+ }
+ } else {
+ if (i >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ break;
+ }
+ }
+ }
+
if (glyphs[i].font_rid != RID()) {
font_draw_glyph(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color);
} else if (hex_codes && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
@@ -1182,15 +1215,44 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
}
}
}
+ // Draw LTR ellipsis string when needed.
+ if (!rtl && trim_data.ellipsis_pos >= 0) {
+ for (int i = 0; i < trim_data.ellipsis_glyph_buf.size(); i++) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
+ font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+ } else {
+ ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+ }
+ }
+ }
+ }
}
void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, int p_outline_size, const Color &p_color) const {
const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
+ bool rtl = (shaped_text_get_direction(p_shaped) == DIRECTION_RTL);
+ TrimData trim_data = shaped_text_get_trim_data(p_shaped);
+
int v_size = visual.size();
const Glyph *glyphs = visual.ptr();
Vector2 ofs = p_pos;
+ // Draw RTL ellipsis string when needed.
+ if (rtl && trim_data.ellipsis_pos >= 0) {
+ for (int i = trim_data.ellipsis_glyph_buf.size() - 1; i >= 0; i--) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
+ font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+ } else {
+ ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+ }
+ }
+ }
+ }
// Draw at the baseline.
for (int i = 0; i < v_size; i++) {
for (int j = 0; j < glyphs[i].repeat; j++) {
@@ -1220,6 +1282,17 @@ void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vect
}
}
}
+ if (trim_data.trim_pos >= 0) {
+ if (rtl) {
+ if (i < trim_data.trim_pos) {
+ continue;
+ }
+ } else {
+ if (i >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+ break;
+ }
+ }
+ }
if (glyphs[i].font_rid != RID()) {
font_draw_glyph_outline(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, p_outline_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color);
}
@@ -1230,6 +1303,19 @@ void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vect
}
}
}
+ // Draw LTR ellipsis string when needed.
+ if (!rtl && trim_data.ellipsis_pos >= 0) {
+ for (int i = 0; i < trim_data.ellipsis_glyph_buf.size(); i++) {
+ for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
+ font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+ if (orientation == ORIENTATION_HORIZONTAL) {
+ ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+ } else {
+ ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+ }
+ }
+ }
+ }
}
RID TextServer::_create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size) {
diff --git a/servers/text_server.h b/servers/text_server.h
index d824504bf4..26993838a3 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -59,7 +59,8 @@ public:
JUSTIFICATION_KASHIDA = 1 << 0,
JUSTIFICATION_WORD_BOUND = 1 << 1,
JUSTIFICATION_TRIM_EDGE_SPACES = 1 << 2,
- JUSTIFICATION_AFTER_LAST_TAB = 1 << 3
+ JUSTIFICATION_AFTER_LAST_TAB = 1 << 3,
+ JUSTIFICATION_CONSTRAIN_ELLIPSIS = 1 << 4,
};
enum LineBreakFlag {
@@ -67,7 +68,7 @@ public:
BREAK_MANDATORY = 1 << 4,
BREAK_WORD_BOUND = 1 << 5,
BREAK_GRAPHEME_BOUND = 1 << 6,
- BREAK_WORD_BOUND_ADAPTIVE = 1 << 5 | 1 << 7
+ BREAK_WORD_BOUND_ADAPTIVE = 1 << 5 | 1 << 7,
};
enum TextOverrunFlag {
@@ -75,7 +76,8 @@ public:
OVERRUN_TRIM = 1 << 0,
OVERRUN_TRIM_WORD_ONLY = 1 << 1,
OVERRUN_ADD_ELLIPSIS = 1 << 2,
- OVERRUN_ENFORCE_ELLIPSIS = 1 << 3
+ OVERRUN_ENFORCE_ELLIPSIS = 1 << 3,
+ OVERRUN_JUSTIFICATION_AWARE = 1 << 4,
};
enum GraphemeFlag {
@@ -154,6 +156,12 @@ public:
}
};
+ struct TrimData {
+ int trim_pos = -1;
+ int ellipsis_pos = -1;
+ Vector<TextServer::Glyph> ellipsis_glyph_buf;
+ };
+
struct ShapedTextData {
/* Source data */
RID parent; // Substring parent ShapedTextData.
@@ -192,6 +200,7 @@ public:
bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted).
bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string.
bool sort_valid = false;
+ bool text_trimmed = false;
bool preserve_invalid = true; // Draw hex code box instead of missing characters.
bool preserve_control = false; // Draw control characters.
@@ -199,10 +208,14 @@ public:
float ascent = 0.f; // Ascent for horizontal layout, 1/2 of width for vertical.
float descent = 0.f; // Descent for horizontal layout, 1/2 of width for vertical.
float width = 0.f; // Width for horizontal layout, height for vertical.
+ float width_trimmed = 0.f;
float upos = 0.f;
float uthk = 0.f;
+ TrimData overrun_trim_data;
+ bool fit_width_minimum_reached = false;
+
Vector<TextServer::Glyph> glyphs;
Vector<TextServer::Glyph> glyphs_logical;
};
@@ -357,7 +370,8 @@ public:
virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const;
virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_clip_flags) = 0;
+ virtual TrimData shaped_text_get_trim_data(RID p_shaped) const;
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint8_t p_trim_flags) = 0;
virtual Array shaped_text_get_objects(RID p_shaped) const = 0;
virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const = 0;