diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/SCsub | 1 | ||||
-rw-r--r-- | core/core_bind.cpp | 10 | ||||
-rw-r--r-- | core/core_bind.h | 2 | ||||
-rw-r--r-- | core/extension/gdextension.cpp | 56 | ||||
-rw-r--r-- | core/extension/gdextension.h | 4 | ||||
-rw-r--r-- | core/io/file_access.cpp | 1 | ||||
-rw-r--r-- | core/io/file_access.h | 1 | ||||
-rw-r--r-- | core/io/file_access_compressed.h | 1 | ||||
-rw-r--r-- | core/io/file_access_encrypted.h | 1 | ||||
-rw-r--r-- | core/io/file_access_memory.h | 1 | ||||
-rw-r--r-- | core/io/file_access_pack.h | 1 | ||||
-rw-r--r-- | core/io/file_access_zip.h | 1 | ||||
-rw-r--r-- | core/io/json.cpp | 4 | ||||
-rw-r--r-- | core/io/resource_saver.cpp | 2 | ||||
-rw-r--r-- | core/math/basis.cpp | 2 | ||||
-rw-r--r-- | core/math/basis.h | 2 | ||||
-rw-r--r-- | core/math/delaunay_3d.h | 77 | ||||
-rw-r--r-- | core/math/geometry_2d.cpp | 111 | ||||
-rw-r--r-- | core/os/os.h | 9 | ||||
-rw-r--r-- | core/os/shared_object.h | 51 | ||||
-rw-r--r-- | core/string/char_utils.h | 2 | ||||
-rw-r--r-- | core/string/translation.cpp | 2 | ||||
-rw-r--r-- | core/variant/variant_parser.cpp | 4 |
23 files changed, 232 insertions, 114 deletions
diff --git a/core/SCsub b/core/SCsub index f7b733a221..ec4658e8ca 100644 --- a/core/SCsub +++ b/core/SCsub @@ -61,7 +61,6 @@ thirdparty_misc_sources = [ # C++ sources "pcg.cpp", "polypartition.cpp", - "clipper.cpp", "smolv.cpp", ] thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources] diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 03c31bee28..364b016ddd 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -152,12 +152,10 @@ void ResourceLoader::_bind_methods() { ////// ResourceSaver ////// Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, BitField<SaverFlags> p_flags) { - ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path '" + p_path + "'."); return ::ResourceSaver::save(p_resource, p_path, p_flags); } Vector<String> ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource) { - ERR_FAIL_COND_V_MSG(p_resource.is_null(), Vector<String>(), "It's not a reference to a valid Resource object."); List<String> exts; ::ResourceSaver::get_recognized_extensions(p_resource, &exts); Vector<String> ret; @@ -1533,6 +1531,10 @@ StringName ClassDB::class_get_integer_constant_enum(const StringName &p_class, c return ::ClassDB::get_integer_constant_enum(p_class, p_name, p_no_inheritance); } +bool ClassDB::is_class_enum_bitfield(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance) const { + return ::ClassDB::is_enum_bitfield(p_class, p_enum, p_no_inheritance); +} + bool ClassDB::is_class_enabled(const StringName &p_class) const { return ::ClassDB::is_class_enabled(p_class); } @@ -1549,7 +1551,7 @@ void ClassDB::get_argument_options(const StringName &p_function, int p_idx, List pf == "class_has_method" || pf == "class_get_method_list" || pf == "class_get_integer_constant_list" || pf == "class_has_integer_constant" || pf == "class_get_integer_constant" || pf == "class_has_enum" || pf == "class_get_enum_list" || pf == "class_get_enum_constants" || pf == "class_get_integer_constant_enum" || - pf == "is_class_enabled"); + pf == "is_class_enabled" || pf == "is_class_enum_bitfield"); } if (first_argument_is_class || pf == "is_parent_class") { for (const String &E : get_class_list()) { @@ -1594,6 +1596,8 @@ void ClassDB::_bind_methods() { ::ClassDB::bind_method(D_METHOD("class_get_enum_constants", "class", "enum", "no_inheritance"), &ClassDB::class_get_enum_constants, DEFVAL(false)); ::ClassDB::bind_method(D_METHOD("class_get_integer_constant_enum", "class", "name", "no_inheritance"), &ClassDB::class_get_integer_constant_enum, DEFVAL(false)); + ::ClassDB::bind_method(D_METHOD("is_class_enum_bitfield", "class", "enum", "no_inheritance"), &ClassDB::is_class_enum_bitfield, DEFVAL(false)); + ::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled); } diff --git a/core/core_bind.h b/core/core_bind.h index 3c0cdc25ce..73c817f43c 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -462,6 +462,8 @@ public: PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const; StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const; + bool is_class_enum_bitfield(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const; + bool is_class_enabled(const StringName &p_class) const; #ifdef TOOLS_ENABLED diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 546c40e9cb..abf4adbc0d 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -46,6 +46,41 @@ String GDExtension::get_extension_list_config_file() { return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg"); } +Vector<SharedObject> GDExtension::find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature) { + Vector<SharedObject> dependencies_shared_objects; + if (p_config->has_section("dependencies")) { + List<String> config_dependencies; + p_config->get_section_keys("dependencies", &config_dependencies); + + for (const String &dependency : config_dependencies) { + Vector<String> dependency_tags = dependency.split("."); + bool all_tags_met = true; + for (int i = 0; i < dependency_tags.size(); i++) { + String tag = dependency_tags[i].strip_edges(); + if (!p_has_feature(tag)) { + all_tags_met = false; + break; + } + } + + if (all_tags_met) { + Dictionary dependency_value = p_config->get_value("dependencies", dependency); + for (const Variant *key = dependency_value.next(nullptr); key; key = dependency_value.next(key)) { + String dependency_path = *key; + String target_path = dependency_value[*key]; + if (dependency_path.is_relative_path()) { + dependency_path = p_path.get_base_dir().path_join(dependency_path); + } + dependencies_shared_objects.push_back(SharedObject(dependency_path, dependency_tags, target_path)); + } + break; + } + } + } + + return dependencies_shared_objects; +} + String GDExtension::find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags) { // First, check the explicit libraries. if (p_config->has_section("libraries")) { @@ -727,10 +762,24 @@ GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(const String return *function; } -Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) { +Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol, Vector<SharedObject> *p_dependencies) { String abs_path = ProjectSettings::get_singleton()->globalize_path(p_path); + + Vector<String> abs_dependencies_paths; + if (p_dependencies != nullptr && !p_dependencies->is_empty()) { + for (const SharedObject &dependency : *p_dependencies) { + abs_dependencies_paths.push_back(ProjectSettings::get_singleton()->globalize_path(dependency.path)); + } + } + String actual_lib_path; - Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, true, &actual_lib_path, Engine::get_singleton()->is_editor_hint()); + OS::GDExtensionData data = { + true, // also_set_library_path + &actual_lib_path, // r_resolved_path + Engine::get_singleton()->is_editor_hint(), // generate_temp_files + &abs_dependencies_paths, // library_dependencies + }; + Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, &data); if (actual_lib_path.get_file() != abs_path.get_file()) { // If temporary files are generated, let's change the library path to point at the original, @@ -970,7 +1019,8 @@ Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path, FileAccess::get_modified_time(library_path)); #endif - err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol); + Vector<SharedObject> library_dependencies = GDExtension::find_extension_dependencies(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); }); + err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol, &library_dependencies); if (err != OK) { // Unreference the extension so that this loading can be considered a failure. p_extension.unref(); diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 1f48edecf7..23b1f51208 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -37,6 +37,7 @@ #include "core/io/config_file.h" #include "core/io/resource_loader.h" #include "core/object/ref_counted.h" +#include "core/os/shared_object.h" class GDExtensionMethodBind; @@ -123,8 +124,9 @@ public: static String get_extension_list_config_file(); static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr); + static Vector<SharedObject> find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature); - Error open_library(const String &p_path, const String &p_entry_symbol); + Error open_library(const String &p_path, const String &p_entry_symbol, Vector<SharedObject> *p_dependencies = nullptr); void close_library(); enum InitializationLevel { diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index d2a5103953..1cf388b33a 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -867,6 +867,7 @@ void FileAccess::_bind_methods() { ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes); ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string); + ClassDB::bind_method(D_METHOD("resize", "length"), &FileAccess::resize); ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush); ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path); ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute); diff --git a/core/io/file_access.h b/core/io/file_access.h index 0b631f68b1..2ab84db4b6 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -166,6 +166,7 @@ public: virtual Error get_error() const = 0; ///< get last error + virtual Error resize(int64_t p_length) = 0; virtual void flush() = 0; virtual void store_8(uint8_t p_dest) = 0; ///< store a byte virtual void store_16(uint16_t p_dest); ///< store 16 bits uint diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index bf57eaa07c..f706c82f8e 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -88,6 +88,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 489d213b8f..42afe49a5e 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -78,6 +78,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index d9efb354c3..e9fbc26d75 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -61,6 +61,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_byte) override; ///< store a byte virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 0deacfebab..594ac8f089 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -177,6 +177,7 @@ public: virtual Error get_error() const override; + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index e9ea74e01d..88b63e93e2 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -100,6 +100,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte diff --git a/core/io/json.cpp b/core/io/json.cpp index 5a1fe45f70..61051727c1 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -344,10 +344,10 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to r_token.value = number; return OK; - } else if (is_ascii_char(p_str[index])) { + } else if (is_ascii_alphabet_char(p_str[index])) { String id; - while (is_ascii_char(p_str[index])) { + while (is_ascii_alphabet_char(p_str[index])) { id += p_str[index]; index++; } diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index e4022b2073..1dc1245355 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -98,6 +98,7 @@ void ResourceFormatSaver::_bind_methods() { } Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) { + ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path '" + p_path + "'."); String path = p_path; if (path.is_empty()) { path = p_resource->get_path(); @@ -174,6 +175,7 @@ void ResourceSaver::set_save_callback(ResourceSavedCallback p_callback) { } void ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) { + ERR_FAIL_COND_MSG(p_resource.is_null(), "It's not a reference to a valid Resource object."); for (int i = 0; i < saver_count; i++) { saver[i]->get_recognized_extensions(p_resource, p_extensions); } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 84ac878172..34ed1c2d85 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -293,7 +293,7 @@ Vector3 Basis::get_scale_abs() const { Vector3(rows[0][2], rows[1][2], rows[2][2]).length()); } -Vector3 Basis::get_scale_local() const { +Vector3 Basis::get_scale_global() const { real_t det_sign = SIGN(determinant()); return det_sign * Vector3(rows[0].length(), rows[1].length(), rows[2].length()); } diff --git a/core/math/basis.h b/core/math/basis.h index 79f3bda8f8..918cbc18d4 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -103,7 +103,7 @@ struct _NO_DISCARD_ Basis { Vector3 get_scale() const; Vector3 get_scale_abs() const; - Vector3 get_scale_local() const; + Vector3 get_scale_global() const; void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale); void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EulerOrder::YXZ); diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index 45571fb570..25bd4e8d89 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -46,7 +46,8 @@ class Delaunay3D { struct Simplex; enum { - ACCEL_GRID_SIZE = 16 + ACCEL_GRID_SIZE = 16, + QUANTIZATION_MAX = 1 << 16 // A power of two smaller than the 23 bit significand of a float. }; struct GridPos { Vector3i pos; @@ -173,38 +174,25 @@ class Delaunay3D { R128 radius2 = rel2_x * rel2_x + rel2_y * rel2_y + rel2_z * rel2_z; - return radius2 < (p_simplex.circum_r2 - R128(0.00001)); + return radius2 < (p_simplex.circum_r2 - R128(0.0000000001)); + // When this tolerance is too big, it can result in overlapping simplices. + // When it's too small, large amounts of planar simplices are created. } static bool simplex_is_coplanar(const Vector3 *p_points, const Simplex &p_simplex) { - Plane p(p_points[p_simplex.points[0]], p_points[p_simplex.points[1]], p_points[p_simplex.points[2]]); - if (ABS(p.distance_to(p_points[p_simplex.points[3]])) < CMP_EPSILON) { - return true; + // Checking every possible distance like this is overkill, but only checking + // one is not enough. If the simplex is almost planar then the vectors p1-p2 + // and p1-p3 can be practically collinear, which makes Plane unreliable. + for (uint32_t i = 0; i < 4; i++) { + Plane p(p_points[p_simplex.points[i]], p_points[p_simplex.points[(i + 1) % 4]], p_points[p_simplex.points[(i + 2) % 4]]); + // This tolerance should not be smaller than the one used with + // Plane::has_point() when creating the LightmapGI probe BSP tree. + if (ABS(p.distance_to(p_points[p_simplex.points[(i + 3) % 4]])) < 0.001) { + return true; + } } - Projection cm; - - cm.columns[0][0] = p_points[p_simplex.points[0]].x; - cm.columns[0][1] = p_points[p_simplex.points[1]].x; - cm.columns[0][2] = p_points[p_simplex.points[2]].x; - cm.columns[0][3] = p_points[p_simplex.points[3]].x; - - cm.columns[1][0] = p_points[p_simplex.points[0]].y; - cm.columns[1][1] = p_points[p_simplex.points[1]].y; - cm.columns[1][2] = p_points[p_simplex.points[2]].y; - cm.columns[1][3] = p_points[p_simplex.points[3]].y; - - cm.columns[2][0] = p_points[p_simplex.points[0]].z; - cm.columns[2][1] = p_points[p_simplex.points[1]].z; - cm.columns[2][2] = p_points[p_simplex.points[2]].z; - cm.columns[2][3] = p_points[p_simplex.points[3]].z; - - cm.columns[3][0] = 1.0; - cm.columns[3][1] = 1.0; - cm.columns[3][2] = 1.0; - cm.columns[3][3] = 1.0; - - return ABS(cm.determinant()) <= CMP_EPSILON; + return false; } public: @@ -215,9 +203,10 @@ public: static Vector<OutputSimplex> tetrahedralize(const Vector<Vector3> &p_points) { uint32_t point_count = p_points.size(); Vector3 *points = (Vector3 *)memalloc(sizeof(Vector3) * (point_count + 4)); + const Vector3 *src_points = p_points.ptr(); + Vector3 proportions; { - const Vector3 *src_points = p_points.ptr(); AABB rect; for (uint32_t i = 0; i < point_count; i++) { Vector3 point = src_points[i]; @@ -226,17 +215,25 @@ public: } else { rect.expand_to(point); } - points[i] = point; } + real_t longest_axis = rect.size[rect.get_longest_axis_index()]; + proportions = Vector3(longest_axis, longest_axis, longest_axis) / rect.size; + for (uint32_t i = 0; i < point_count; i++) { - points[i] = (points[i] - rect.position) / rect.size; + // Scale points to the unit cube to better utilize R128 precision + // and quantize to stabilize triangulation over a wide range of + // distances. + points[i] = Vector3(Vector3i((src_points[i] - rect.position) / longest_axis * QUANTIZATION_MAX)) / QUANTIZATION_MAX; } - const real_t delta_max = Math::sqrt(2.0) * 20.0; + const real_t delta_max = Math::sqrt(2.0) * 100.0; Vector3 center = Vector3(0.5, 0.5, 0.5); - // any simplex that contains everything is good + // The larger the root simplex is, the more likely it is that the + // triangulation is convex. If it's not absolutely huge, there can + // be missing simplices that are not created for the outermost faces + // of the point cloud if the point density is very low there. points[point_count + 0] = center + Vector3(0, 1, 0) * delta_max; points[point_count + 1] = center + Vector3(0, -1, 1) * delta_max; points[point_count + 2] = center + Vector3(1, -1, -1) * delta_max; @@ -271,7 +268,7 @@ public: for (uint32_t i = 0; i < point_count; i++) { bool unique = true; for (uint32_t j = i + 1; j < point_count; j++) { - if (points[i].is_equal_approx(points[j])) { + if (points[i] == points[j]) { unique = false; break; } @@ -280,7 +277,7 @@ public: continue; } - Vector3i grid_pos = Vector3i(points[i] * ACCEL_GRID_SIZE); + Vector3i grid_pos = Vector3i(points[i] * proportions * ACCEL_GRID_SIZE); grid_pos = grid_pos.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1)); for (List<Simplex *>::Element *E = acceleration_grid[grid_pos.x][grid_pos.y][grid_pos.z].front(); E;) { @@ -300,6 +297,9 @@ public: Triangle t = Triangle(simplex->points[triangle_order[k][0]], simplex->points[triangle_order[k][1]], simplex->points[triangle_order[k][2]]); uint32_t *p = triangles_inserted.lookup_ptr(t); if (p) { + // This Delaunay implementation uses the Bowyer-Watson algorithm. + // The rule is that you don't reuse any triangles that were + // shared by any of the retriangulated simplices. triangles[*p].bad = true; } else { triangles_inserted.insert(t, triangles.size()); @@ -307,7 +307,6 @@ public: } } - //remove simplex and continue simplex_list.erase(simplex->SE); for (const GridPos &gp : simplex->grid_positions) { @@ -334,8 +333,8 @@ public: const real_t radius2 = Math::sqrt(double(new_simplex->circum_r2)) + 0.0001; Vector3 extents = Vector3(radius2, radius2, radius2); - Vector3i from = Vector3i((center - extents) * ACCEL_GRID_SIZE); - Vector3i to = Vector3i((center + extents) * ACCEL_GRID_SIZE); + Vector3i from = Vector3i((center - extents) * proportions * ACCEL_GRID_SIZE); + Vector3i to = Vector3i((center + extents) * proportions * ACCEL_GRID_SIZE); from = from.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1)); to = to.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1)); @@ -370,7 +369,7 @@ public: break; } } - if (invalid || simplex_is_coplanar(points, *simplex)) { + if (invalid || simplex_is_coplanar(src_points, *simplex)) { memdelete(simplex); continue; } diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp index 602e95bc13..d60619b27f 100644 --- a/core/math/geometry_2d.cpp +++ b/core/math/geometry_2d.cpp @@ -30,12 +30,12 @@ #include "geometry_2d.h" -#include "thirdparty/misc/clipper.hpp" +#include "thirdparty/clipper2/include/clipper2/clipper.h" #include "thirdparty/misc/polypartition.h" #define STB_RECT_PACK_IMPLEMENTATION #include "thirdparty/misc/stb_rect_pack.h" -#define SCALE_FACTOR 100000.0 // Based on CMP_EPSILON. +#define PRECISION 5 // Based on CMP_EPSILON. Vector<Vector<Vector2>> Geometry2D::decompose_polygon_in_convex(const Vector<Point2> &polygon) { Vector<Vector<Vector2>> decomp; @@ -196,58 +196,59 @@ void Geometry2D::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_re } Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open) { - using namespace ClipperLib; + using namespace Clipper2Lib; - ClipType op = ctUnion; + ClipType op = ClipType::Union; switch (p_op) { case OPERATION_UNION: - op = ctUnion; + op = ClipType::Union; break; case OPERATION_DIFFERENCE: - op = ctDifference; + op = ClipType::Difference; break; case OPERATION_INTERSECTION: - op = ctIntersection; + op = ClipType::Intersection; break; case OPERATION_XOR: - op = ctXor; + op = ClipType::Xor; break; } - Path path_a, path_b; - // Need to scale points (Clipper's requirement for robust computation). + PathD path_a(p_polypath_a.size()); for (int i = 0; i != p_polypath_a.size(); ++i) { - path_a << IntPoint(p_polypath_a[i].x * (real_t)SCALE_FACTOR, p_polypath_a[i].y * (real_t)SCALE_FACTOR); + path_a[i] = PointD(p_polypath_a[i].x, p_polypath_a[i].y); } + PathD path_b(p_polypath_b.size()); for (int i = 0; i != p_polypath_b.size(); ++i) { - path_b << IntPoint(p_polypath_b[i].x * (real_t)SCALE_FACTOR, p_polypath_b[i].y * (real_t)SCALE_FACTOR); + path_b[i] = PointD(p_polypath_b[i].x, p_polypath_b[i].y); } - Clipper clp; - clp.AddPath(path_a, ptSubject, !is_a_open); // Forward compatible with Clipper 10.0.0. - clp.AddPath(path_b, ptClip, true); // Polylines cannot be set as clip. - Paths paths; + ClipperD clp(PRECISION); // Scale points up internally to attain the desired precision. + clp.PreserveCollinear(false); // Remove redundant vertices. + if (is_a_open) { + clp.AddOpenSubject({ path_a }); + } else { + clp.AddSubject({ path_a }); + } + clp.AddClip({ path_b }); + + PathsD paths; if (is_a_open) { - PolyTree tree; // Needed to populate polylines. - clp.Execute(op, tree); - OpenPathsFromPolyTree(tree, paths); + PolyTreeD tree; // Needed to populate polylines. + clp.Execute(op, FillRule::EvenOdd, tree, paths); } else { - clp.Execute(op, paths); // Works on closed polygons only. + clp.Execute(op, FillRule::EvenOdd, paths); // Works on closed polygons only. } - // Have to scale points down now. + Vector<Vector<Point2>> polypaths; + for (PathsD::size_type i = 0; i < paths.size(); ++i) { + const PathD &path = paths[i]; - for (Paths::size_type i = 0; i < paths.size(); ++i) { Vector<Vector2> polypath; - - const Path &scaled_path = paths[i]; - - for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { - polypath.push_back(Point2( - static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR, - static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR)); + for (PathsD::size_type j = 0; j < path.size(); ++j) { + polypath.push_back(Point2(static_cast<real_t>(path[j].x), static_cast<real_t>(path[j].y))); } polypaths.push_back(polypath); } @@ -255,67 +256,61 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation } Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { - using namespace ClipperLib; + using namespace Clipper2Lib; - JoinType jt = jtSquare; + JoinType jt = JoinType::Square; switch (p_join_type) { case JOIN_SQUARE: - jt = jtSquare; + jt = JoinType::Square; break; case JOIN_ROUND: - jt = jtRound; + jt = JoinType::Round; break; case JOIN_MITER: - jt = jtMiter; + jt = JoinType::Miter; break; } - EndType et = etClosedPolygon; + EndType et = EndType::Polygon; switch (p_end_type) { case END_POLYGON: - et = etClosedPolygon; + et = EndType::Polygon; break; case END_JOINED: - et = etClosedLine; + et = EndType::Joined; break; case END_BUTT: - et = etOpenButt; + et = EndType::Butt; break; case END_SQUARE: - et = etOpenSquare; + et = EndType::Square; break; case END_ROUND: - et = etOpenRound; + et = EndType::Round; break; } - ClipperOffset co(2.0, 0.25f * (real_t)SCALE_FACTOR); // Defaults from ClipperOffset. - Path path; - // Need to scale points (Clipper's requirement for robust computation). + PathD polypath(p_polypath.size()); for (int i = 0; i != p_polypath.size(); ++i) { - path << IntPoint(p_polypath[i].x * (real_t)SCALE_FACTOR, p_polypath[i].y * (real_t)SCALE_FACTOR); + polypath[i] = PointD(p_polypath[i].x, p_polypath[i].y); } - co.AddPath(path, jt, et); - Paths paths; - co.Execute(paths, p_delta * (real_t)SCALE_FACTOR); // Inflate/deflate. + // Inflate/deflate. + PathsD paths = InflatePaths({ polypath }, p_delta, jt, et, 2.0, PRECISION, 0.0); + // Here the miter_limit = 2.0 and arc_tolerance = 0.0 are Clipper2 defaults, + // and the PRECISION is used to scale points up internally, to attain the desired precision. - // Have to scale points down now. Vector<Vector<Point2>> polypaths; + for (PathsD::size_type i = 0; i < paths.size(); ++i) { + const PathD &path = paths[i]; - for (Paths::size_type i = 0; i < paths.size(); ++i) { - Vector<Vector2> polypath; - - const Path &scaled_path = paths[i]; - - for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { - polypath.push_back(Point2( - static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR, - static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR)); + Vector<Vector2> polypath2; + for (PathsD::size_type j = 0; j < path.size(); ++j) { + polypath2.push_back(Point2(static_cast<real_t>(path[j].x), static_cast<real_t>(path[j].y))); } - polypaths.push_back(polypath); + polypaths.push_back(polypath2); } return polypaths; } diff --git a/core/os/os.h b/core/os/os.h index 06be0e2b41..069a3876af 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -153,7 +153,14 @@ public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); - virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr, bool p_generate_temp_files = false) { return ERR_UNAVAILABLE; } + struct GDExtensionData { + bool also_set_library_path = false; + String *r_resolved_path = nullptr; + bool generate_temp_files = false; + PackedStringArray *library_dependencies = nullptr; + }; + + virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data = nullptr) { return ERR_UNAVAILABLE; } virtual Error close_dynamic_library(void *p_library_handle) { return ERR_UNAVAILABLE; } virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional = false) { return ERR_UNAVAILABLE; } diff --git a/core/os/shared_object.h b/core/os/shared_object.h new file mode 100644 index 0000000000..88423bed13 --- /dev/null +++ b/core/os/shared_object.h @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* shared_object.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef SHARED_OBJECT_H +#define SHARED_OBJECT_H + +#include "core/string/ustring.h" +#include "core/templates/vector.h" + +struct SharedObject { + String path; + Vector<String> tags; + String target; + + SharedObject(const String &p_path, const Vector<String> &p_tags, const String &p_target) : + path(p_path), + tags(p_tags), + target(p_target) { + } + + SharedObject() {} +}; + +#endif // SHARED_OBJECT_H diff --git a/core/string/char_utils.h b/core/string/char_utils.h index aa9bc198ca..fc2fbb95a1 100644 --- a/core/string/char_utils.h +++ b/core/string/char_utils.h @@ -92,7 +92,7 @@ static _FORCE_INLINE_ bool is_binary_digit(char32_t c) { return (c == '0' || c == '1'); } -static _FORCE_INLINE_ bool is_ascii_char(char32_t c) { +static _FORCE_INLINE_ bool is_ascii_alphabet_char(char32_t c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 613edd11cd..344fe42fa0 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -993,7 +993,7 @@ String TranslationServer::add_padding(const String &p_message, int p_length) con } const char32_t *TranslationServer::get_accented_version(char32_t p_character) const { - if (!is_ascii_char(p_character)) { + if (!is_ascii_alphabet_char(p_character)) { return nullptr; } diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index dcb94b16b1..06daaab6a2 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -489,11 +489,11 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri r_token.value = num.as_int(); } return OK; - } else if (is_ascii_char(cchar) || is_underscore(cchar)) { + } else if (is_ascii_alphabet_char(cchar) || is_underscore(cchar)) { StringBuffer<> id; bool first = true; - while (is_ascii_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) { + while (is_ascii_alphabet_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) { id += cchar; cchar = p_stream->get_char(); first = false; |