summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/core_bind.cpp2
-rw-r--r--core/io/resource_uid.cpp3
-rw-r--r--doc/classes/OS.xml2
-rw-r--r--editor/editor_dir_dialog.cpp1
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp2
-rw-r--r--modules/bullet/rigid_body_bullet.cpp1
-rw-r--r--modules/bullet/space_bullet.cpp2
-rw-r--r--modules/csg/csg.cpp18
-rw-r--r--modules/enet/enet_multiplayer_peer.cpp2
-rw-r--r--modules/gdscript/gdscript_vm.cpp10
-rw-r--r--modules/gltf/doc_classes/GLTFLight.xml16
-rw-r--r--modules/gltf/gltf_document.cpp6
-rw-r--r--modules/gltf/gltf_light.h8
-rw-r--r--modules/text_server_adv/text_server_adv.cpp1
-rw-r--r--modules/text_server_fb/text_server_fb.cpp1
-rw-r--r--platform/osx/export/export_plugin.cpp53
-rw-r--r--scene/2d/tile_map.cpp14
-rw-r--r--scene/gui/line_edit.cpp13
-rw-r--r--scene/gui/line_edit.h4
-rw-r--r--scene/gui/tabs.cpp28
-rw-r--r--scene/gui/text_edit.cpp4
-rw-r--r--scene/resources/primitive_meshes.cpp6
-rw-r--r--scene/resources/primitive_meshes.h2
-rw-r--r--scene/resources/skeleton_modification_2d.cpp42
-rw-r--r--scene/resources/skeleton_modification_3d.cpp40
-rw-r--r--scene/resources/surface_tool.cpp1
26 files changed, 177 insertions, 105 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 242a2f3638..71c04f7954 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -2221,7 +2221,7 @@ Object *Engine::get_singleton_object(const StringName &p_name) const {
void Engine::register_singleton(const StringName &p_name, Object *p_object) {
ERR_FAIL_COND_MSG(has_singleton(p_name), "Singleton already registered: " + String(p_name));
- ERR_FAIL_COND_MSG(p_name.operator String().is_valid_identifier(), "Singleton name is not a valid identifier: " + String(p_name));
+ ERR_FAIL_COND_MSG(!String(p_name).is_valid_identifier(), "Singleton name is not a valid identifier: " + p_name);
::Engine::Singleton s;
s.class_name = p_name;
s.name = p_name;
diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp
index 97d683f415..290a71043c 100644
--- a/core/io/resource_uid.cpp
+++ b/core/io/resource_uid.cpp
@@ -126,8 +126,7 @@ String ResourceUID::get_id_path(ID p_id) const {
MutexLock l(mutex);
ERR_FAIL_COND_V(!unique_ids.has(p_id), String());
const CharString &cs = unique_ids[p_id].cs;
- String s(cs.ptr());
- return s;
+ return String::utf8(cs.ptr());
}
void ResourceUID::remove_id(ID p_id) {
MutexLock l(mutex);
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index e2ac8568c9..9d0d185c42 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -49,6 +49,7 @@
[/codeblocks]
See [method execute] if you wish to run an external command and retrieve the results.
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
+ [b]Note:[/b] On macOS, sandboxed applications are limited to run only embedded helper executables, specified during export.
</description>
</method>
<method name="delay_msec" qualifiers="const">
@@ -119,6 +120,7 @@
[/csharp]
[/codeblocks]
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
+ [b]Note:[/b] On macOS, sandboxed applications are limited to run only embedded helper executables, specified during export.
</description>
</method>
<method name="find_keycode_from_string" qualifiers="const">
diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp
index 5df392b91e..f91dedf25d 100644
--- a/editor/editor_dir_dialog.cpp
+++ b/editor/editor_dir_dialog.cpp
@@ -44,6 +44,7 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p
p_item->set_metadata(0, p_dir->get_path());
p_item->set_icon(0, tree->get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")));
+ p_item->set_icon_modulate(0, tree->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog")));
if (!p_item->get_parent()) {
p_item->set_text(0, "res://");
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 76a05449db..97dd02870c 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -87,7 +87,7 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list
p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, ""));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "tile_size", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, ""));
}
void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_bind_methods() {
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 0d2cd1f5a0..b511c5f8d8 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -303,6 +303,7 @@ RigidBodyBullet::~RigidBodyBullet() {
void RigidBodyBullet::init_kinematic_utilities() {
kinematic_utilities = memnew(KinematicUtilities(this));
+ reload_kinematic_shapes();
}
void RigidBodyBullet::destroy_kinematic_utilities() {
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index a9a811c445..0cfd658bd5 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -947,7 +947,6 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
if (!p_body->get_kinematic_utilities()) {
p_body->init_kinematic_utilities();
- p_body->reload_kinematic_shapes();
}
btVector3 initial_recover_motion(0, 0, 0);
@@ -1089,7 +1088,6 @@ int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform3D
if (!p_body->get_kinematic_utilities()) {
p_body->init_kinematic_utilities();
- p_body->reload_kinematic_shapes();
}
btVector3 recover_motion(0, 0, 0);
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index cbe41a1310..f7e92aaa90 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -40,13 +40,13 @@ inline static bool is_snapable(const Vector3 &p_point1, const Vector3 &p_point2,
return (p_point1 - p_point2).length_squared() < p_distance * p_distance;
}
-inline static Vector2 interpolate_segment_uv(const Vector2 p_segement_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) {
- float segment_length = (p_segement_points[1] - p_segement_points[0]).length();
- if (p_segement_points[0].is_equal_approx(p_segement_points[1])) {
+inline static Vector2 interpolate_segment_uv(const Vector2 p_segment_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) {
+ float segment_length = (p_segment_points[1] - p_segment_points[0]).length();
+ if (p_segment_points[0].is_equal_approx(p_segment_points[1])) {
return p_uvs[0];
}
- float distance = (p_interpolation_point - p_segement_points[0]).length();
+ float distance = (p_interpolation_point - p_segment_points[0]).length();
float fraction = distance / segment_length;
return p_uvs[0].lerp(p_uvs[1], fraction);
@@ -162,7 +162,7 @@ inline static bool is_triangle_degenerate(const Vector2 p_vertices[3], real_t p_
return det < p_vertex_snap2;
}
-inline static bool are_segements_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) {
+inline static bool are_segments_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) {
Vector2 segment1 = p_segment1_points[1] - p_segment1_points[0];
Vector2 segment2 = p_segment2_points[1] - p_segment2_points[0];
real_t segment1_length2 = segment1.dot(segment1);
@@ -911,7 +911,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
vertices[outer_edge_idx[1]].point,
vertices[p_segment_indices[closest_idx]].point
};
- if (are_segements_parallel(edge1, edge2, vertex_snap2)) {
+ if (are_segments_parallel(edge1, edge2, vertex_snap2)) {
if (!degenerate_points.find(outer_edge_idx[0])) {
degenerate_points.push_back(outer_edge_idx[0]);
}
@@ -1056,7 +1056,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
}
// Check if edge exists, by checking if the intersecting segment is parallel to the edge.
- if (are_segements_parallel(p_segment_points, edge_points, vertex_snap2)) {
+ if (are_segments_parallel(p_segment_points, edge_points, vertex_snap2)) {
continue;
}
@@ -1172,8 +1172,8 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
Vector2 split_edge1[2] = { vertices[new_vertex_idx].point, edge_points[0] };
Vector2 split_edge2[2] = { vertices[new_vertex_idx].point, edge_points[1] };
Vector2 new_edge[2] = { vertices[new_vertex_idx].point, vertices[opposite_vertex_idx].point };
- if (are_segements_parallel(split_edge1, new_edge, vertex_snap2) &&
- are_segements_parallel(split_edge2, new_edge, vertex_snap2)) {
+ if (are_segments_parallel(split_edge1, new_edge, vertex_snap2) &&
+ are_segments_parallel(split_edge2, new_edge, vertex_snap2)) {
break;
}
diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp
index afd31207f6..5bdc93dc78 100644
--- a/modules/enet/enet_multiplayer_peer.cpp
+++ b/modules/enet/enet_multiplayer_peer.cpp
@@ -173,7 +173,7 @@ bool ENetMultiplayerPeer::_poll_server() {
emit_signal(SNAME("peer_disconnected"), id);
peers.erase(id);
- if (!server_relay) {
+ if (server_relay) {
_notify_peers(id, false);
}
return false;
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 9ea9fc61de..6186d0edee 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -88,9 +88,9 @@ static String _get_var_type(const Variant *p_var) {
Object *bobj = p_var->get_validated_object_with_check(was_freed);
if (!bobj) {
if (was_freed) {
- basestr = "null instance";
- } else {
basestr = "previously freed";
+ } else {
+ basestr = "null instance";
}
} else {
basestr = bobj->get_class();
@@ -1233,7 +1233,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GD_ERR_BREAK(to_type < 0 || to_type >= Variant::VARIANT_MAX);
#ifdef DEBUG_ENABLED
- if (src->get_type() == Variant::OBJECT && !src->operator ObjectID().is_ref_counted() && ObjectDB::get_instance(src->operator ObjectID()) == nullptr) {
+ if (src->operator Object *() && !src->get_validated_object()) {
err_text = "Trying to cast a freed object.";
OPCODE_BREAK;
}
@@ -1263,7 +1263,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GD_ERR_BREAK(!nc);
#ifdef DEBUG_ENABLED
- if (src->get_type() == Variant::OBJECT && !src->operator ObjectID().is_ref_counted() && ObjectDB::get_instance(src->operator ObjectID()) == nullptr) {
+ if (src->operator Object *() && !src->get_validated_object()) {
err_text = "Trying to cast a freed object.";
OPCODE_BREAK;
}
@@ -1295,7 +1295,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GD_ERR_BREAK(!base_type);
#ifdef DEBUG_ENABLED
- if (src->get_type() == Variant::OBJECT && !src->operator ObjectID().is_ref_counted() && ObjectDB::get_instance(src->operator ObjectID()) == nullptr) {
+ if (src->operator Object *() && !src->get_validated_object()) {
err_text = "Trying to cast a freed object.";
OPCODE_BREAK;
}
diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml
index 91df7d8014..b4f03cd1ed 100644
--- a/modules/gltf/doc_classes/GLTFLight.xml
+++ b/modules/gltf/doc_classes/GLTFLight.xml
@@ -7,17 +7,25 @@
<tutorials>
</tutorials>
<members>
- <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)">
+ <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)">
+ The [Color] of the light. Defaults to white. A black color causes the light to have no effect.
</member>
<member name="inner_cone_angle" type="float" setter="set_inner_cone_angle" getter="get_inner_cone_angle" default="0.0">
+ The inner angle of the cone in a spotlight. Must be less than or equal to the outer cone angle.
+ Within this angle, the light is at full brightness. Between the inner and outer cone angles, there is a transition from full brightness to zero brightness. When creating a Godot [SpotLight3D], the ratio between the inner and outer cone angles is used to calculate the attenuation of the light.
</member>
- <member name="intensity" type="float" setter="set_intensity" getter="get_intensity" default="0.0">
+ <member name="intensity" type="float" setter="set_intensity" getter="get_intensity" default="1.0">
+ The intensity of the light. This is expressed in candelas (lumens per steradian) for point and spot lights, and lux (lumens per m²) for directional lights. When creating a Godot light, this value is converted to a unitless multiplier.
</member>
<member name="light_type" type="String" setter="set_light_type" getter="get_light_type" default="&quot;&quot;">
+ The type of the light. The values accepted by Godot are "point", "spot", and "directional", which correspond to Godot's [OmniLight3D], [SpotLight3D], and [DirectionalLight3D] respectively.
</member>
- <member name="outer_cone_angle" type="float" setter="set_outer_cone_angle" getter="get_outer_cone_angle" default="0.0">
+ <member name="outer_cone_angle" type="float" setter="set_outer_cone_angle" getter="get_outer_cone_angle" default="0.785398">
+ The outer angle of the cone in a spotlight. Must be greater than or equal to the inner angle.
+ At this angle, the light drops off to zero brightness. Between the inner and outer cone angles, there is a transition from full brightness to zero brightness. If this angle is a half turn, then the spotlight emits in all directions. When creating a Godot [SpotLight3D], the outer cone angle is used as the angle of the spotlight.
</member>
- <member name="range" type="float" setter="set_range" getter="get_range" default="0.0">
+ <member name="range" type="float" setter="set_range" getter="get_range" default="inf">
+ The range of the light, beyond which the light has no effect. GLTF lights with no range defined behave like physical lights (which have infinite range). When creating a Godot light, the range is clamped to 4096.
</member>
</members>
</class>
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index df2856ec7c..97367b15df 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -5074,7 +5074,7 @@ Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent,
const float range = CLAMP(l->range, 0, 4096);
// Doubling the range will double the effective brightness, so we need double attenuation (half brightness).
// We want to have double intensity give double brightness, so we need half the attenuation.
- const float attenuation = range / intensity;
+ const float attenuation = range / (intensity * 2048);
if (l->light_type == "point") {
OmniLight3D *light = memnew(OmniLight3D);
light->set_param(OmniLight3D::PARAM_ATTENUATION, attenuation);
@@ -5150,13 +5150,13 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_lig
OmniLight3D *light = cast_to<OmniLight3D>(p_light);
l->range = light->get_param(OmniLight3D::PARAM_RANGE);
float attenuation = p_light->get_param(OmniLight3D::PARAM_ATTENUATION);
- l->intensity = l->range / attenuation;
+ l->intensity = l->range / (attenuation * 2048);
} else if (cast_to<SpotLight3D>(p_light)) {
l->light_type = "spot";
SpotLight3D *light = cast_to<SpotLight3D>(p_light);
l->range = light->get_param(SpotLight3D::PARAM_RANGE);
float attenuation = light->get_param(SpotLight3D::PARAM_ATTENUATION);
- l->intensity = l->range / attenuation;
+ l->intensity = l->range / (attenuation * 2048);
l->outer_cone_angle = Math::deg2rad(light->get_param(SpotLight3D::PARAM_SPOT_ANGLE));
// This equation is the inverse of the import equation (which has a desmos link).
diff --git a/modules/gltf/gltf_light.h b/modules/gltf/gltf_light.h
index 079fb18151..62a20d2f16 100644
--- a/modules/gltf/gltf_light.h
+++ b/modules/gltf/gltf_light.h
@@ -42,12 +42,12 @@ protected:
static void _bind_methods();
private:
- Color color;
- float intensity = 0.0f;
+ Color color = Color(1.0f, 1.0f, 1.0f);
+ float intensity = 1.0f;
String light_type;
- float range = 0.0f;
+ float range = INFINITY;
float inner_cone_angle = 0.0f;
- float outer_cone_angle = 0.0f;
+ float outer_cone_angle = Math_TAU / 8.0f;
public:
Color get_color();
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index ef1411fb3b..c93f353cea 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -3573,6 +3573,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
shaped_text_shape(p_shaped_line);
}
+ sd->text_trimmed = false;
sd->overrun_trim_data.ellipsis_glyph_buf.clear();
bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 8a1bd93c65..1323aa80ce 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -2683,6 +2683,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
shaped_text_shape(p_shaped_line);
}
+ sd->text_trimmed = false;
sd->overrun_trim_data.ellipsis_glyph_buf.clear();
bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp
index 54a3104482..2404c20153 100644
--- a/platform/osx/export/export_plugin.cpp
+++ b/platform/osx/export/export_plugin.cpp
@@ -95,6 +95,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_pictures", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array()));
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
@@ -535,6 +536,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = ERR_CANT_CREATE;
}
+ Array helpers = p_preset->get("codesign/entitlements/app_sandbox/helper_executables");
+
// Create our folder structure.
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
@@ -546,6 +549,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks");
}
+ if ((err == OK) && helpers.size() > 0) {
+ print_line("Creating " + tmp_app_path_name + "/Contents/Helpers");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Helpers");
+ }
+
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
@@ -688,6 +696,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
bool sign_enabled = p_preset->get("codesign/enable");
String ent_path = p_preset->get("codesign/entitlements/custom_file");
+ String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + "_helper.entitlements");
if (sign_enabled && (ent_path == "")) {
ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
@@ -819,10 +828,43 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
} else {
err = ERR_CANT_CREATE;
}
+
+ if ((err == OK) && helpers.size() > 0) {
+ ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE);
+ if (ent_f) {
+ ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
+ ent_f->store_line("<plist version=\"1.0\">");
+ ent_f->store_line("<dict>");
+ ent_f->store_line("<key>com.apple.security.app-sandbox</key>");
+ ent_f->store_line("<true/>");
+ ent_f->store_line("<key>com.apple.security.inherit</key>");
+ ent_f->store_line("<true/>");
+ ent_f->store_line("</dict>");
+ ent_f->store_line("</plist>");
+
+ ent_f->close();
+ memdelete(ent_f);
+ } else {
+ err = ERR_CANT_CREATE;
+ }
+ }
+ }
+
+ if ((err == OK) && helpers.size() > 0) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ for (int i = 0; i < helpers.size(); i++) {
+ String hlp_path = helpers[i];
+ err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file());
+ if (err == OK && sign_enabled) {
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path);
+ }
+ FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755);
+ }
}
if (err == OK) {
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
if (da->dir_exists(src_path)) {
@@ -842,7 +884,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path);
}
}
- memdelete(da);
}
if (sign_enabled) {
@@ -903,6 +944,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = _notarize(p_preset, p_path);
}
+ // Clean up temporary entitlements files.
+ DirAccess::remove_file_or_error(hlp_ent_path);
+
// Clean up temporary .app dir.
tmp_app_dir->change_dir(tmp_app_path_name);
tmp_app_dir->erase_contents_recursive();
@@ -916,7 +960,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
String dir = p_root_path.plus_file(p_folder);
- DirAccess *da = DirAccess::open(dir);
+ DirAccessRef da = DirAccess::open(dir);
da->list_dir_begin();
String f;
while ((f = da->get_next()) != "") {
@@ -967,7 +1011,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
} else if (da->current_is_dir()) {
_zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
} else {
- bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name));
+ bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers");
OS::Time time = OS::get_singleton()->get_time();
OS::Date date = OS::get_singleton()->get_date();
@@ -1012,7 +1056,6 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
}
}
da->list_dir_end();
- memdelete(da);
}
bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 03db9c0d32..929233e4e0 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -2034,10 +2034,22 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
return false;
} else if (components.size() == 2 && components[0].begins_with("layer_") && components[0].trim_prefix("layer_").is_valid_int()) {
int index = components[0].trim_prefix("layer_").to_int();
- if (index < 0 || index >= (int)layers.size()) {
+ if (index < 0) {
return false;
}
+ if (index >= (int)layers.size()) {
+ _clear_internals();
+ while (index >= (int)layers.size()) {
+ layers.push_back(TileMapLayer());
+ }
+ _recreate_internals();
+
+ notify_property_list_changed();
+ emit_signal(SNAME("changed"));
+ update_configuration_warnings();
+ }
+
if (components[1] == "name") {
set_layer_name(index, p_value);
return true;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index d9acbeb828..09128770d5 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -260,24 +260,29 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
} else {
if (selecting_enabled) {
- if (!b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) {
+ const int triple_click_timeout = 600;
+ const int triple_click_tolerance = 5;
+ const bool is_triple_click = !b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < triple_click_timeout && b->get_position().distance_to(last_dblclk_pos) < triple_click_tolerance;
+
+ if (is_triple_click && text.length()) {
// Triple-click select all.
selection.enabled = true;
selection.begin = 0;
selection.end = text.length();
selection.double_click = true;
- selection.last_dblclk = 0;
+ last_dblclk = 0;
caret_column = selection.begin;
} else if (b->is_double_click()) {
// Double-click select word.
+ last_dblclk = OS::get_singleton()->get_ticks_msec();
+ last_dblclk_pos = b->get_position();
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
for (int i = 0; i < words.size(); i++) {
- if (words[i].x < caret_column && words[i].y > caret_column) {
+ if ((words[i].x < caret_column && words[i].y > caret_column) || (i == words.size() - 1 && caret_column == words[i].y)) {
selection.enabled = true;
selection.begin = words[i].x;
selection.end = words[i].y;
selection.double_click = true;
- selection.last_dblclk = OS::get_singleton()->get_ticks_msec();
caret_column = selection.end;
break;
}
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index e364a79c83..9f28c84f50 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -136,7 +136,6 @@ private:
bool creating = false;
bool double_click = false;
bool drag_attempt = false;
- uint64_t last_dblclk = 0;
} selection;
struct TextOperation {
@@ -153,6 +152,9 @@ private:
bool pressing_inside = false;
} clear_button_status;
+ uint64_t last_dblclk = 0;
+ Vector2 last_dblclk_pos;
+
bool caret_blink_enabled = false;
bool caret_force_displayed = false;
bool draw_caret = true;
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 7faa9aca2c..ef34bec347 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -98,29 +98,45 @@ void Tabs::gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) {
Point2 pos = mm->get_position();
- highlight_arrow = -1;
if (buttons_visible) {
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
if (is_layout_rtl()) {
if (pos.x < decr->get_width()) {
- highlight_arrow = 1;
+ if (highlight_arrow != 1) {
+ highlight_arrow = 1;
+ update();
+ }
} else if (pos.x < incr->get_width() + decr->get_width()) {
- highlight_arrow = 0;
+ if (highlight_arrow != 0) {
+ highlight_arrow = 0;
+ update();
+ }
+ } else if (highlight_arrow != -1) {
+ highlight_arrow = -1;
+ update();
}
} else {
int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
if (pos.x > limit_minus_buttons + decr->get_width()) {
- highlight_arrow = 1;
+ if (highlight_arrow != 1) {
+ highlight_arrow = 1;
+ update();
+ }
} else if (pos.x > limit_minus_buttons) {
- highlight_arrow = 0;
+ if (highlight_arrow != 0) {
+ highlight_arrow = 0;
+ update();
+ }
+ } else if (highlight_arrow != -1) {
+ highlight_arrow = -1;
+ update();
}
}
}
_update_hover();
- update();
return;
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 09899413f2..5b13e1da0b 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -3689,7 +3689,7 @@ void TextEdit::select_word_under_caret() {
int end = 0;
const Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
for (int i = 0; i < words.size(); i++) {
- if (words[i].x <= caret.column && words[i].y >= caret.column) {
+ if ((words[i].x < caret.column && words[i].y > caret.column) || (i == words.size() - 1 && caret.column == words[i].y)) {
begin = words[i].x;
end = words[i].y;
break;
@@ -5411,7 +5411,7 @@ void TextEdit::_update_selection_mode_word() {
int end = beg;
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
for (int i = 0; i < words.size(); i++) {
- if (words[i].x < caret_pos && words[i].y > caret_pos) {
+ if ((words[i].x < caret_pos && words[i].y > caret_pos) || (i == words.size() - 1 && caret_pos == words[i].y)) {
beg = words[i].x;
end = words[i].y;
break;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index e7da41db9d..25eb701596 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -1390,6 +1390,12 @@ void QuadMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset");
}
+uint32_t QuadMesh::surface_get_format(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, 1, 0);
+
+ return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV;
+}
+
QuadMesh::QuadMesh() {
primitive_type = PRIMITIVE_TRIANGLES;
}
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 7915cb0028..d447dad97a 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -285,6 +285,8 @@ protected:
virtual void _create_mesh_array(Array &p_arr) const override;
public:
+ virtual uint32_t surface_get_format(int p_idx) const override;
+
QuadMesh();
void set_size(const Size2 &p_size);
diff --git a/scene/resources/skeleton_modification_2d.cpp b/scene/resources/skeleton_modification_2d.cpp
index e533fb054a..7ac40b497d 100644
--- a/scene/resources/skeleton_modification_2d.cpp
+++ b/scene/resources/skeleton_modification_2d.cpp
@@ -96,37 +96,25 @@ float SkeletonModification2D::clamp_angle(float p_angle, float p_min_bound, floa
p_max_bound = Math_TAU + p_max_bound;
}
if (p_min_bound > p_max_bound) {
- float tmp = p_min_bound;
- p_min_bound = p_max_bound;
- p_max_bound = tmp;
+ SWAP(p_min_bound, p_max_bound);
}
+ bool is_beyond_bounds = (p_angle < p_min_bound || p_angle > p_max_bound);
+ bool is_within_bounds = (p_angle > p_min_bound && p_angle < p_max_bound);
+
// Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle.
- if (p_invert == false) {
- if (p_angle < p_min_bound || p_angle > p_max_bound) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
-
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
- }
- } else {
- if (p_angle > p_min_bound && p_angle < p_max_bound) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
+ if ((!p_invert && is_beyond_bounds) || (p_invert && is_within_bounds)) {
+ Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
+ Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
+ Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
+ if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
+ p_angle = p_min_bound;
+ } else {
+ p_angle = p_max_bound;
}
}
+
return p_angle;
}
@@ -152,9 +140,7 @@ void SkeletonModification2D::editor_draw_angle_constraints(Bone2D *p_operation_b
arc_angle_max = (Math_PI * 2) + arc_angle_max;
}
if (arc_angle_min > arc_angle_max) {
- float tmp = arc_angle_min;
- arc_angle_min = arc_angle_max;
- arc_angle_max = tmp;
+ SWAP(arc_angle_min, arc_angle_max);
}
arc_angle_min += p_operation_bone->get_bone_angle();
arc_angle_max += p_operation_bone->get_bone_angle();
diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp
index ee02ede2d5..b476952d86 100644
--- a/scene/resources/skeleton_modification_3d.cpp
+++ b/scene/resources/skeleton_modification_3d.cpp
@@ -72,37 +72,25 @@ real_t SkeletonModification3D::clamp_angle(real_t p_angle, real_t p_min_bound, r
p_max_bound = Math_TAU + p_max_bound;
}
if (p_min_bound > p_max_bound) {
- real_t tmp = p_min_bound;
- p_min_bound = p_max_bound;
- p_max_bound = tmp;
+ SWAP(p_min_bound, p_max_bound);
}
+ bool is_beyond_bounds = (p_angle < p_min_bound || p_angle > p_max_bound);
+ bool is_within_bounds = (p_angle > p_min_bound && p_angle < p_max_bound);
+
// Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle.
- if (p_invert == false) {
- if (p_angle < p_min_bound || p_angle > p_max_bound) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
-
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
- }
- } else {
- if (p_angle > p_min_bound && p_angle < p_max_bound) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
-
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
+ if ((!p_invert && is_beyond_bounds) || (p_invert && is_within_bounds)) {
+ Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
+ Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
+ Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
+
+ if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
+ p_angle = p_min_bound;
+ } else {
+ p_angle = p_max_bound;
}
}
+
return p_angle;
}
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index d5e370568d..a8cd872408 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -1176,6 +1176,7 @@ Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_coun
ERR_FAIL_COND_V(simplify_func == nullptr, lod);
ERR_FAIL_COND_V(vertex_array.size() == 0, lod);
ERR_FAIL_COND_V(index_array.size() == 0, lod);
+ ERR_FAIL_COND_V(index_array.size() % 3 != 0, lod);
lod.resize(index_array.size());
LocalVector<float> vertices; //uses floats