summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/CharacterBody2D.xml3
-rw-r--r--doc/classes/CharacterBody3D.xml3
-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/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--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/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/text_server.cpp88
-rw-r--r--servers/text_server.h22
65 files changed, 1035 insertions, 2106 deletions
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/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/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/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/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/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;