summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bullet/SCsub2
-rw-r--r--modules/bullet/bullet_physics_server.cpp4
-rw-r--r--modules/bullet/bullet_physics_server.h2
-rw-r--r--modules/bullet/godot_result_callbacks.cpp4
-rw-r--r--modules/bullet/godot_result_callbacks.h4
-rw-r--r--modules/bullet/rigid_body_bullet.cpp10
-rw-r--r--modules/bullet/rigid_body_bullet.h2
-rw-r--r--modules/bullet/space_bullet.cpp16
-rw-r--r--modules/bullet/space_bullet.h4
-rw-r--r--modules/csg/csg_shape.h4
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp4
-rw-r--r--modules/fbx/data/fbx_mesh_data.h2
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp22
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp17
-rw-r--r--modules/gdnative/text/text_server_gdnative.cpp8
-rw-r--r--modules/gdnative/text/text_server_gdnative.h6
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp4
-rw-r--r--modules/gltf/gltf_document.cpp12
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp4
-rw-r--r--modules/navigation/navigation_mesh_generator.h2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp448
-rw-r--r--modules/text_server_adv/text_server_adv.h7
-rw-r--r--modules/text_server_fb/text_server_fb.cpp391
-rw-r--r--modules/text_server_fb/text_server_fb.h7
-rw-r--r--modules/vhacd/register_types.cpp2
-rw-r--r--modules/visual_script/visual_script_editor.h2
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp2
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp6
-rw-r--r--modules/visual_script/visual_script_yield_nodes.h6
30 files changed, 556 insertions, 450 deletions
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub
index bfac0df5b0..ba57de303e 100644
--- a/modules/bullet/SCsub
+++ b/modules/bullet/SCsub
@@ -12,6 +12,8 @@ thirdparty_obj = []
if env["builtin_bullet"]:
# Build only version 2 for now (as of 2.89)
# Sync file list with relevant upstream CMakeLists.txt for each folder.
+ if env["float"] == "64":
+ env.Append(CPPDEFINES=["BT_USE_DOUBLE_PRECISION=1"])
thirdparty_dir = "#thirdparty/bullet/"
bullet2_src = [
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index e07be14c5b..fc876a81cf 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -842,12 +842,12 @@ PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_bod
return BulletPhysicsDirectBodyState3D::get_singleton(body);
}
-bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
- return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes);
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes, p_exclude);
}
int BulletPhysicsServer3D::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) {
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index d34d619ba2..7f0934e679 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -253,7 +253,7 @@ public:
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
- virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, 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;
/* SOFT BODY API */
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 399b102284..1f962772e7 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -135,6 +135,10 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox
if (m_self_object->has_collision_exception(gObj) || gObj->has_collision_exception(m_self_object)) {
return false;
}
+
+ if (m_exclude->has(gObj->get_self())) {
+ return false;
+ }
}
return true;
} else {
diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h
index 9216322108..96a649d77a 100644
--- a/modules/bullet/godot_result_callbacks.h
+++ b/modules/bullet/godot_result_callbacks.h
@@ -100,11 +100,13 @@ public:
struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
public:
const RigidBodyBullet *m_self_object;
+ const Set<RID> *m_exclude;
const bool m_infinite_inertia;
- GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia) :
+ GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia, const Set<RID> *p_exclude) :
btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld),
m_self_object(p_self_object),
+ m_exclude(p_exclude),
m_infinite_inertia(p_infinite_inertia) {}
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index ce39d4f0df..0d2cd1f5a0 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -114,6 +114,16 @@ Transform3D BulletPhysicsDirectBodyState3D::get_transform() const {
return body->get_transform();
}
+Vector3 BulletPhysicsDirectBodyState3D::get_velocity_at_local_position(const Vector3 &p_position) const {
+ btVector3 local_position;
+ G_TO_B(p_position, local_position);
+
+ Vector3 velocity;
+ B_TO_G(body->btBody->getVelocityInLocalPoint(local_position), velocity);
+
+ return velocity;
+}
+
void BulletPhysicsDirectBodyState3D::add_central_force(const Vector3 &p_force) {
body->apply_central_force(p_force);
}
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index 606df7134b..5e102d8b05 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -110,6 +110,8 @@ public:
virtual void set_transform(const Transform3D &p_transform) override;
virtual Transform3D get_transform() const override;
+ virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const override;
+
virtual void add_central_force(const Vector3 &p_force) override;
virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override;
virtual void add_torque(const Vector3 &p_torque) override;
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 583900e6bc..c6d835742d 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -908,7 +908,7 @@ static Ref<StandardMaterial3D> red_mat;
static Ref<StandardMaterial3D> blue_mat;
#endif
-bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
#if debug_test_motion
/// Yes I know this is not good, but I've used it as fast debugging hack.
/// I'm leaving it here just for speedup the other eventual debugs
@@ -948,7 +948,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
btVector3 initial_recover_motion(0, 0, 0);
{ /// Phase one - multi shapes depenetration using margin
for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) {
- if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion)) {
+ if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion, nullptr, p_exclude)) {
break;
}
}
@@ -1000,7 +1000,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
break;
}
- GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia);
+ GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia, &p_exclude);
btResult.m_collisionFilterGroup = p_body->get_collision_layer();
btResult.m_collisionFilterMask = p_body->get_collision_mask();
@@ -1023,7 +1023,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
btVector3 __rec(0, 0, 0);
RecoverResult r_recover_result;
- has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result);
+ has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result, p_exclude);
// Parse results
if (r_result) {
@@ -1173,7 +1173,7 @@ public:
}
};
-bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) {
+bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result, const Set<RID> &p_exclude) {
// Calculate the cumulative AABB of all shapes of the kinematic body
btVector3 aabb_min, aabb_max;
bool shapes_found = false;
@@ -1242,6 +1242,12 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran
for (int i = recover_broad_result.results.size() - 1; 0 <= i; --i) {
btCollisionObject *otherObject = recover_broad_result.results[i].collision_object;
+
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(otherObject->getUserPointer());
+ if (p_exclude.has(gObj->get_self())) {
+ continue;
+ }
+
if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) {
otherObject->activate(); // Force activation of hitten rigid, soft body
continue;
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
index 36d0538e6b..2070e0e633 100644
--- a/modules/bullet/space_bullet.h
+++ b/modules/bullet/space_bullet.h
@@ -188,7 +188,7 @@ public:
real_t get_linear_damp() const { return linear_damp; }
real_t get_angular_damp() const { return angular_damp; }
- bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes);
+ bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>());
int test_ray_separation(RigidBodyBullet *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);
private:
@@ -209,7 +209,7 @@ private:
RecoverResult() {}
};
- bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
+ bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr, const Set<RID> &p_exclude = Set<RID>());
/// This is an API that recover a kinematic object from penetration
/// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions
bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index de7de09f00..0106f230eb 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -83,14 +83,14 @@ private:
Vector<Vector3> vertices;
Vector<Vector3> normals;
Vector<Vector2> uvs;
- Vector<float> tans;
+ Vector<real_t> tans;
Ref<Material> material;
int last_added = 0;
Vector3 *verticesw = nullptr;
Vector3 *normalsw = nullptr;
Vector2 *uvsw = nullptr;
- float *tansw = nullptr;
+ real_t *tansw = nullptr;
};
//mikktspace callbacks
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index 8b4b1e08b3..dcea476275 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -433,7 +433,7 @@ void FBXMeshData::sanitize_vertex_weights(const ImportState &state) {
{
// Sort
- real_t *weights_ptr = vm->weights.ptrw();
+ float *weights_ptr = vm->weights.ptrw();
int *bones_ptr = vm->bones.ptrw();
for (int i = 0; i < vm->weights.size(); i += 1) {
for (int x = i + 1; x < vm->weights.size(); x += 1) {
@@ -449,7 +449,7 @@ void FBXMeshData::sanitize_vertex_weights(const ImportState &state) {
// Resize
vm->weights.resize(max_vertex_influence_count);
vm->bones.resize(max_vertex_influence_count);
- real_t *weights_ptr = vm->weights.ptrw();
+ float *weights_ptr = vm->weights.ptrw();
int *bones_ptr = vm->bones.ptrw();
for (int i = initial_size; i < max_vertex_influence_count; i += 1) {
weights_ptr[i] = 0.0;
diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h
index 7486c5c59c..24db4a5469 100644
--- a/modules/fbx/data/fbx_mesh_data.h
+++ b/modules/fbx/data/fbx_mesh_data.h
@@ -64,7 +64,7 @@ struct SurfaceData {
};
struct VertexWeightMapping {
- Vector<real_t> weights;
+ Vector<float> weights;
Vector<int> bones;
// This extra vector is used because the bone id is computed in a second step.
// TODO Get rid of this extra step is a good idea.
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index f3a0e9603f..26d3aed702 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -114,9 +114,25 @@ void NativeScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder)
#endif
bool NativeScript::inherits_script(const Ref<Script> &p_script) const {
-#ifndef _MSC_VER
-#warning inheritance needs to be implemented in NativeScript
-#endif
+ Ref<NativeScript> ns = p_script;
+ if (ns.is_null()) {
+ return false;
+ }
+
+ const NativeScriptDesc *other_s = ns->get_script_desc();
+ if (!other_s) {
+ return false;
+ }
+
+ const NativeScriptDesc *s = get_script_desc();
+
+ while (s) {
+ if (s == other_s) {
+ return true;
+ }
+ s = s->base_data;
+ }
+
return false;
}
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
index 7fc8178e34..5380858582 100644
--- a/modules/gdnative/pluginscript/pluginscript_script.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -139,9 +139,20 @@ bool PluginScript::can_instantiate() const {
}
bool PluginScript::inherits_script(const Ref<Script> &p_script) const {
-#ifndef _MSC_VER
-#warning inheritance needs to be implemented in PluginScript
-#endif
+ Ref<PluginScript> ps = p_script;
+ if (ps.is_null()) {
+ return false;
+ }
+
+ const PluginScript *s = this;
+
+ while (s) {
+ if (s == p_script.ptr()) {
+ return true;
+ }
+ s = Object::cast_to<PluginScript>(s->_ref_base_parent.ptr());
+ }
+
return false;
}
diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp
index 81dd570bcb..3ed3f5449e 100644
--- a/modules/gdnative/text/text_server_gdnative.cpp
+++ b/modules/gdnative/text/text_server_gdnative.cpp
@@ -449,12 +449,12 @@ bool TextServerGDNative::shaped_text_add_string(RID p_shaped, const String &p_te
return interface->shaped_text_add_string(data, (godot_rid *)&p_shaped, (const godot_string *)&p_text, (const godot_rid **)p_fonts.ptr(), p_size, (const godot_dictionary *)&p_opentype_features, (const godot_string *)&p_language);
}
-bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
+bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->shaped_text_add_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align, p_length);
}
-bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
+bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->shaped_text_resize_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align);
}
@@ -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 7a0725f3d9..e1b36f4264 100644
--- a/modules/gdnative/text/text_server_gdnative.h
+++ b/modules/gdnative/text/text_server_gdnative.h
@@ -154,8 +154,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
- virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
- virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override;
+ virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;
@@ -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/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 7c9d08b782..fe827a5b72 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -107,7 +107,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
// Locate class by constructing the path to it and following that path
GDScriptParser::ClassNode *class_type = p_datatype.class_type;
if (class_type) {
- if (class_type->fqcn.begins_with(main_script->path) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) {
+ if ((!main_script->path.is_empty() && class_type->fqcn.begins_with(main_script->path)) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) {
// Local class.
List<StringName> names;
while (class_type->outer) {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index a500dfd51a..a21167ad95 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -2480,7 +2480,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
switch (dictionary->style) {
case DictionaryNode::LUA_TABLE:
if (key != nullptr && key->type != Node::IDENTIFIER) {
- push_error("Expected identifier as dictionary key.");
+ push_error("Expected identifier as LUA-style dictionary key.");
+ advance();
+ break;
}
if (!match(GDScriptTokenizer::Token::EQUAL)) {
if (match(GDScriptTokenizer::Token::COLON)) {
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index be44f66423..ff0579a11c 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -43,6 +43,7 @@
#include "gltf_texture.h"
#include "core/crypto/crypto_core.h"
+#include "core/error/error_macros.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/json.h"
@@ -4469,9 +4470,9 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
const Dictionary &spot = d["spot"];
light->inner_cone_angle = spot["innerConeAngle"];
light->outer_cone_angle = spot["outerConeAngle"];
- ERR_FAIL_COND_V_MSG(light->inner_cone_angle >= light->outer_cone_angle, ERR_PARSE_ERROR, "The inner angle must be smaller than the outer angle.");
+ ERR_CONTINUE_MSG(light->inner_cone_angle >= light->outer_cone_angle, "The inner angle must be smaller than the outer angle.");
} else if (type != "point" && type != "directional") {
- ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Light type is unknown.");
+ ERR_CONTINUE_MSG(ERR_PARSE_ERROR, "Light type is unknown.");
}
state->lights.push_back(light);
@@ -5380,15 +5381,16 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent
// and attach it to the bone_attachment
scene_parent = bone_attachment;
}
-
- // We still have not managed to make a node
if (gltf_node->mesh >= 0) {
current_node = _generate_mesh_instance(state, scene_parent, node_index);
} else if (gltf_node->camera >= 0) {
current_node = _generate_camera(state, scene_parent, node_index);
} else if (gltf_node->light >= 0) {
current_node = _generate_light(state, scene_parent, node_index);
- } else {
+ }
+
+ // We still have not managed to make a node.
+ if (!current_node) {
current_node = _generate_spatial(state, scene_parent, node_index);
}
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 41cd75fd22..74da939e6f 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -138,7 +138,7 @@ void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, cons
}
}
-void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) {
+void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) {
if (Object::cast_to<MeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) {
MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_node);
Ref<Mesh> mesh = mesh_instance->get_mesh();
@@ -515,7 +515,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node)
Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse();
for (Node *E : parse_nodes) {
- int geometry_type = p_nav_mesh->get_parsed_geometry_type();
+ NavigationMesh::ParsedGeometryType geometry_type = p_nav_mesh->get_parsed_geometry_type();
uint32_t collision_mask = p_nav_mesh->get_collision_mask();
bool recurse_children = p_nav_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT;
_parse_geometry(navmesh_xform, E, vertices, indices, geometry_type, collision_mask, recurse_children);
diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h
index 847c7d097b..78f1329e3f 100644
--- a/modules/navigation/navigation_mesh_generator.h
+++ b/modules/navigation/navigation_mesh_generator.h
@@ -52,7 +52,7 @@ protected:
static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies);
static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices);
- static void _parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children);
+ static void _parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children);
static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh);
static void _build_recast_navigation_mesh(
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index fa4888f843..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);
@@ -1161,7 +1163,7 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te
return true;
}
-bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
+bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -1191,7 +1193,7 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con
return true;
}
-bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
+bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -1222,34 +1224,10 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[key].rect.position.x = sd->width;
sd->width += sd->objects[key].rect.size.x;
- switch (sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
- } break;
- }
sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
} else {
sd->objects[key].rect.position.y = sd->width;
sd->width += sd->objects[key].rect.size.y;
- switch (sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
- } break;
- }
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
}
} else {
@@ -1279,35 +1257,71 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
// Align embedded objects to baseline.
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = sd->descent;
+ } break;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
+ sd->ascent = full_ascent;
+ sd->descent = full_descent;
}
return true;
}
@@ -1363,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);
@@ -1404,33 +1418,9 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
- switch (new_sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
- new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
- } break;
- }
} else {
new_sd->objects[key].rect.position.y = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.y;
- switch (new_sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
- new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
- } break;
- }
}
} else {
if (prev_rid != gl.font_rid) {
@@ -1464,37 +1454,72 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
// Align embedded objects to baseline.
+ float full_ascent = new_sd->ascent;
+ float full_descent = new_sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -new_sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = new_sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = new_sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -new_sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = new_sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = new_sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
+ new_sd->ascent = full_ascent;
+ new_sd->descent = full_descent;
}
-
new_sd->valid = true;
return shaped_owner.make_rid(new_sd);
@@ -1518,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;
@@ -1546,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;
}
@@ -1574,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) {
@@ -1582,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;
}
@@ -1662,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.");
@@ -1670,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;
}
@@ -1688,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;
@@ -1710,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;
@@ -1728,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;
@@ -1736,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;
@@ -1755,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++;
- }
+ 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);
}
- // 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);
- }
- }
-
- // 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);
@@ -1843,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)) {
@@ -1907,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();
@@ -2027,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])) {
@@ -2100,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;
}
@@ -2166,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;
@@ -2309,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;
@@ -2473,33 +2504,9 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[span.embedded_key].rect.position.x = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.x;
- switch (sd->objects[span.embedded_key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
- } break;
- }
} else {
sd->objects[span.embedded_key].rect.position.y = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.y;
- switch (sd->objects[span.embedded_key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
- } break;
- }
}
Glyph gl;
gl.start = span.start;
@@ -2539,34 +2546,69 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
// Align embedded objects to baseline.
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
-
+ sd->ascent = full_ascent;
+ sd->descent = full_descent;
sd->valid = true;
return sd->valid;
}
@@ -2643,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));
}
}
@@ -2676,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 3c4f840bfd..d19ba41a1a 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -216,8 +216,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
- virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
- virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override;
+ virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;
@@ -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 004cbc2bb3..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 {
@@ -661,7 +661,7 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te
return true;
}
-bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
+bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -691,7 +691,7 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con
return true;
}
-bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
+bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -724,34 +724,10 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[key].rect.position.x = sd->width;
sd->width += sd->objects[key].rect.size.x;
- switch (sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
- } break;
- }
sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
} else {
sd->objects[key].rect.position.y = sd->width;
sd->width += sd->objects[key].rect.size.y;
- switch (sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
- } break;
- }
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
}
} else {
@@ -784,35 +760,71 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
// Align embedded objects to baseline.
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = sd->descent;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = sd->descent;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
+ sd->ascent = full_ascent;
+ sd->descent = full_descent;
}
return true;
}
@@ -869,33 +881,9 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
- switch (new_sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
- new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
- } break;
- }
} else {
new_sd->objects[key].rect.position.y = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.y;
- switch (new_sd->objects[key].inline_align) {
- case VALIGN_TOP: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
- new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
- } break;
- }
}
} else {
const FontDataFallback *fd = font_owner.getornull(gl.font_rid);
@@ -923,35 +911,72 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
}
+ // Align embedded objects to baseline.
+ float full_ascent = new_sd->ascent;
+ float full_descent = new_sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -new_sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = new_sd->descent;
+ } break;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = new_sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -new_sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
+ } break;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = new_sd->descent;
+ } break;
+ }
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = new_sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
} break;
}
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
+ new_sd->ascent = full_ascent;
+ new_sd->descent = full_descent;
}
new_sd->valid = true;
@@ -1148,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.");
@@ -1156,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;
}
@@ -1174,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;
@@ -1214,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);
@@ -1336,33 +1328,9 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[span.embedded_key].rect.position.x = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.x;
- switch (sd->objects[span.embedded_key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
- } break;
- }
} else {
sd->objects[span.embedded_key].rect.position.y = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.y;
- switch (sd->objects[span.embedded_key].inline_align) {
- case VALIGN_TOP: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
- } break;
- case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
- sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
- } break;
- case VALIGN_BOTTOM: {
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
- } break;
- }
}
Glyph gl;
gl.start = span.start;
@@ -1456,34 +1424,69 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
}
// Align embedded objects to baseline.
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.y = -(E->get().rect.size.y / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.y = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.y = sd->descent - E->get().rect.size.y;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.y = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.y -= E->get().rect.size.y / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.y);
+ full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
- switch (E->get().inline_align) {
- case VALIGN_TOP: {
+ switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
- case VALIGN_CENTER: {
- E->get().rect.position.x = -(E->get().rect.size.x / 2);
+ case INLINE_ALIGN_TO_CENTER: {
+ E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ } break;
+ case INLINE_ALIGN_TO_BASELINE: {
+ E->get().rect.position.x = 0;
} break;
- case VALIGN_BOTTOM: {
- E->get().rect.position.x = sd->descent - E->get().rect.size.x;
+ case INLINE_ALIGN_TO_BOTTOM: {
+ E->get().rect.position.x = sd->descent;
} break;
}
+ switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ case INLINE_ALIGN_BOTTOM_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x;
+ } break;
+ case INLINE_ALIGN_CENTER_TO: {
+ E->get().rect.position.x -= E->get().rect.size.x / 2;
+ } break;
+ case INLINE_ALIGN_TOP_TO: {
+ //NOP
+ } break;
+ }
+ full_ascent = MAX(full_ascent, -E->get().rect.position.x);
+ full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
-
+ sd->ascent = full_ascent;
+ sd->descent = full_descent;
sd->valid = true;
return sd->valid;
}
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index b70c8f4ec0..d4cab2409a 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -165,8 +165,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
- virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
- virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override;
+ virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
+ virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;
@@ -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/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp
index 3d7aaee921..2b48e94604 100644
--- a/modules/vhacd/register_types.cpp
+++ b/modules/vhacd/register_types.cpp
@@ -33,7 +33,7 @@
#include "thirdparty/vhacd/public/VHACD.h"
static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, int p_max_convex_hulls = -1) {
- Vector<float> vertices;
+ Vector<real_t> vertices;
vertices.resize(p_faces.size() * 9);
Vector<uint32_t> indices;
indices.resize(p_faces.size() * 3);
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 3b7ed3dba6..962ea380aa 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -60,7 +60,7 @@ class VisualScriptEditor : public ScriptEditorBase {
EDIT_CUT_NODES,
EDIT_PASTE_NODES,
EDIT_CREATE_FUNCTION,
- REFRESH_GRAPH
+ REFRESH_GRAPH,
};
enum PortAction {
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index 8bf1c6cbfa..bacb1947be 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -74,6 +74,8 @@ void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
current->select(0);
} break;
+ default:
+ break;
}
}
}
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index 9fa49b8a1d..cded1e587c 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -93,7 +93,7 @@ String VisualScriptYield::get_text() const {
class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance {
public:
VisualScriptYield::YieldMode mode;
- float wait_time;
+ double wait_time;
virtual int get_working_memory_size() const { return 1; } //yield needs at least 1
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
@@ -159,7 +159,7 @@ VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode() {
return yield_mode;
}
-void VisualScriptYield::set_wait_time(float p_time) {
+void VisualScriptYield::set_wait_time(double p_time) {
if (wait_time == p_time) {
return;
}
@@ -167,7 +167,7 @@ void VisualScriptYield::set_wait_time(float p_time) {
ports_changed_notify();
}
-float VisualScriptYield::get_wait_time() {
+double VisualScriptYield::get_wait_time() {
return wait_time;
}
diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h
index fa596173a6..6005ff30b0 100644
--- a/modules/visual_script/visual_script_yield_nodes.h
+++ b/modules/visual_script/visual_script_yield_nodes.h
@@ -47,7 +47,7 @@ public:
private:
YieldMode yield_mode;
- float wait_time;
+ double wait_time;
protected:
virtual void _validate_property(PropertyInfo &property) const override;
@@ -73,8 +73,8 @@ public:
void set_yield_mode(YieldMode p_mode);
YieldMode get_yield_mode();
- void set_wait_time(float p_time);
- float get_wait_time();
+ void set_wait_time(double p_time);
+ double get_wait_time();
virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;