summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub13
-rw-r--r--core/array.cpp4
-rw-r--r--core/array.h2
-rw-r--r--core/bind/core_bind.cpp200
-rw-r--r--core/bind/core_bind.h66
-rw-r--r--core/class_db.cpp18
-rw-r--r--core/class_db.h2
-rw-r--r--core/color_names.inc1
-rw-r--r--core/command_queue_mt.h4
-rw-r--r--core/core_string_names.cpp1
-rw-r--r--core/core_string_names.h1
-rw-r--r--core/dictionary.cpp4
-rw-r--r--core/dictionary.h2
-rw-r--r--core/error_macros.h8
-rw-r--r--core/func_ref.cpp13
-rw-r--r--core/func_ref.h1
-rw-r--r--core/image.cpp178
-rw-r--r--core/image.h1
-rw-r--r--core/io/compression.cpp6
-rw-r--r--core/io/file_access_buffered_fa.h8
-rw-r--r--core/io/file_access_compressed.cpp13
-rw-r--r--core/io/file_access_compressed.h2
-rw-r--r--core/io/file_access_encrypted.cpp11
-rw-r--r--core/io/file_access_encrypted.h2
-rw-r--r--core/io/file_access_memory.h2
-rw-r--r--core/io/file_access_network.cpp15
-rw-r--r--core/io/file_access_network.h2
-rw-r--r--core/io/file_access_pack.cpp2
-rw-r--r--core/io/file_access_pack.h2
-rw-r--r--core/io/file_access_zip.h2
-rw-r--r--core/io/http_client.cpp2
-rw-r--r--core/io/image_loader.cpp3
-rw-r--r--core/io/marshalls.cpp58
-rw-r--r--core/io/marshalls.h4
-rw-r--r--core/io/multiplayer_api.cpp71
-rw-r--r--core/io/multiplayer_api.h4
-rw-r--r--core/io/packet_peer.cpp18
-rw-r--r--core/io/packet_peer.h7
-rw-r--r--core/io/resource_format_binary.cpp3
-rw-r--r--core/io/resource_importer.cpp10
-rw-r--r--core/io/resource_importer.h5
-rw-r--r--core/io/resource_loader.cpp24
-rw-r--r--core/io/resource_loader.h2
-rw-r--r--core/io/stream_peer.cpp14
-rw-r--r--core/io/stream_peer.h4
-rw-r--r--core/io/zip_io.h2
-rw-r--r--core/list.h10
-rw-r--r--core/make_binders.py12
-rw-r--r--core/math/a_star.cpp103
-rw-r--r--core/math/a_star.h26
-rw-r--r--core/math/audio_frame.h15
-rw-r--r--core/math/basis.cpp55
-rw-r--r--core/math/basis.h3
-rw-r--r--core/math/camera_matrix.cpp8
-rw-r--r--core/math/camera_matrix.h1
-rw-r--r--core/math/delaunay.h4
-rw-r--r--core/math/expression.cpp33
-rw-r--r--core/math/expression.h2
-rw-r--r--core/math/geometry.cpp108
-rw-r--r--core/math/geometry.h109
-rw-r--r--core/math/math_funcs.h40
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/plane.h4
-rw-r--r--core/math/quat.h8
-rw-r--r--core/math/random_number_generator.cpp1
-rw-r--r--core/math/random_number_generator.h2
-rw-r--r--core/math/random_pcg.cpp3
-rw-r--r--core/math/random_pcg.h15
-rw-r--r--core/math/rect2.h41
-rw-r--r--core/math/transform_2d.cpp2
-rw-r--r--core/math/transform_2d.h2
-rw-r--r--core/math/vector2.h16
-rw-r--r--core/math/vector3.h30
-rw-r--r--core/message_queue.cpp22
-rw-r--r--core/message_queue.h2
-rw-r--r--core/method_bind.h6
-rw-r--r--core/object.cpp47
-rw-r--r--core/object.h9
-rw-r--r--core/ordered_hash_map.h4
-rw-r--r--core/os/dir_access.cpp2
-rw-r--r--core/os/file_access.cpp55
-rw-r--r--core/os/file_access.h10
-rw-r--r--core/os/input.cpp9
-rw-r--r--core/os/input.h4
-rw-r--r--core/os/input_event.cpp13
-rw-r--r--core/os/main_loop.h28
-rw-r--r--core/os/midi_driver.cpp5
-rw-r--r--core/os/os.cpp13
-rw-r--r--core/os/os.h12
-rw-r--r--core/packed_data_container.cpp9
-rw-r--r--core/print_string.cpp2
-rw-r--r--core/project_settings.cpp33
-rw-r--r--core/reference.h19
-rw-r--r--core/resource.cpp20
-rw-r--r--core/resource.h10
-rw-r--r--core/script_language.cpp1
-rw-r--r--core/script_language.h7
-rw-r--r--core/string_builder.h4
-rw-r--r--core/translation.cpp33
-rw-r--r--core/translation.h2
-rw-r--r--core/type_info.h122
-rw-r--r--core/typedefs.h27
-rw-r--r--core/ucaps.h1332
-rw-r--r--core/undo_redo.cpp24
-rw-r--r--core/undo_redo.h5
-rw-r--r--core/ustring.cpp82
-rw-r--r--core/ustring.h22
-rw-r--r--core/variant.cpp67
-rw-r--r--core/variant.h1
-rw-r--r--core/variant_call.cpp29
-rw-r--r--core/variant_op.cpp12
-rw-r--r--core/variant_parser.cpp6
-rw-r--r--core/vmap.h2
-rw-r--r--core/vset.h2
114 files changed, 2490 insertions, 1098 deletions
diff --git a/core/SCsub b/core/SCsub
index 00d0bcac24..166b7083e4 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -58,6 +58,7 @@ thirdparty_misc_sources = [
"md5.cpp",
"pcg.cpp",
"triangulator.cpp",
+ "clipper.cpp",
]
thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
env_thirdparty.add_source_files(env.core_sources, thirdparty_misc_sources)
@@ -80,9 +81,9 @@ if env['builtin_zlib']:
]
thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
- env_thirdparty.Append(CPPPATH=[thirdparty_zlib_dir])
+ env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir])
# Needs to be available in main env too
- env.Append(CPPPATH=[thirdparty_zlib_dir])
+ env.Prepend(CPPPATH=[thirdparty_zlib_dir])
env_thirdparty.add_source_files(env.core_sources, thirdparty_zlib_sources)
@@ -128,11 +129,11 @@ if env['builtin_zstd']:
]
thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
- env_thirdparty.Append(CPPPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"])
- env_thirdparty.Append(CCFLAGS="-DZSTD_STATIC_LINKING_ONLY")
- env.Append(CPPPATH=thirdparty_zstd_dir)
+ env_thirdparty.Prepend(CPPPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"])
+ env_thirdparty.Append(CPPFLAGS="-DZSTD_STATIC_LINKING_ONLY")
+ env.Prepend(CPPPATH=thirdparty_zstd_dir)
# Also needed in main env includes will trigger warnings
- env.Append(CCFLAGS="-DZSTD_STATIC_LINKING_ONLY")
+ env.Append(CPPFLAGS="-DZSTD_STATIC_LINKING_ONLY")
env_thirdparty.add_source_files(env.core_sources, thirdparty_zstd_sources)
diff --git a/core/array.cpp b/core/array.cpp
index 649e610a69..65934d6ec9 100644
--- a/core/array.cpp
+++ b/core/array.cpp
@@ -401,6 +401,10 @@ Variant Array::max() const {
return maxval;
}
+const void *Array::id() const {
+ return _p->array.ptr();
+}
+
Array::Array(const Array &p_from) {
_p = NULL;
diff --git a/core/array.h b/core/array.h
index 6158db4065..d4e937a486 100644
--- a/core/array.h
+++ b/core/array.h
@@ -94,6 +94,8 @@ public:
Variant min() const;
Variant max() const;
+ const void *id() const;
+
Array(const Array &p_from);
Array();
~Array();
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index f5dbacd62d..dbfa04be4d 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -148,7 +148,7 @@ _ResourceLoader::_ResourceLoader() {
singleton = this;
}
-Error _ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error _ResourceSaver::save(const String &p_path, const RES &p_resource, SaverFlags p_flags) {
ERR_FAIL_COND_V(p_resource.is_null(), ERR_INVALID_PARAMETER);
return ResourceSaver::save(p_path, p_resource, p_flags);
@@ -442,14 +442,14 @@ Error _OS::shell_open(String p_uri) {
return OS::get_singleton()->shell_open(p_uri);
};
-int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output) {
+int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output, bool p_read_stderr) {
OS::ProcessID pid = -2;
List<String> args;
for (int i = 0; i < p_arguments.size(); i++)
args.push_back(p_arguments[i]);
String pipe;
- Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe);
+ Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe, NULL, p_read_stderr);
p_output.clear();
p_output.push_back(pipe);
if (err != OK)
@@ -611,6 +611,11 @@ uint64_t _OS::get_dynamic_memory_usage() const {
return OS::get_singleton()->get_dynamic_memory_usage();
}
+void _OS::set_native_icon(const String &p_filename) {
+
+ OS::get_singleton()->set_native_icon(p_filename);
+}
+
void _OS::set_icon(const Ref<Image> &p_icon) {
OS::get_singleton()->set_icon(p_icon);
@@ -792,7 +797,7 @@ Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const {
size_t imonth = 0;
- while (dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) {
+ while ((unsigned long)dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) {
dayno -= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth];
imonth++;
}
@@ -1178,7 +1183,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_processor_count"), &_OS::get_processor_count);
ClassDB::bind_method(D_METHOD("get_executable_path"), &_OS::get_executable_path);
- ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output"), &_OS::execute, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output", "read_stderr"), &_OS::execute, DEFVAL(Array()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("kill", "pid"), &_OS::kill);
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &_OS::shell_open);
ClassDB::bind_method(D_METHOD("get_process_id"), &_OS::get_process_id);
@@ -1199,6 +1204,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_system_time_secs"), &_OS::get_system_time_secs);
ClassDB::bind_method(D_METHOD("get_system_time_msecs"), &_OS::get_system_time_msecs);
+ ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &_OS::set_native_icon);
ClassDB::bind_method(D_METHOD("set_icon", "icon"), &_OS::set_icon);
ClassDB::bind_method(D_METHOD("get_exit_code"), &_OS::get_exit_code);
@@ -1491,11 +1497,21 @@ PoolVector<Vector3> _Geometry::segment_intersects_convex(const Vector3 &p_from,
return r;
}
+bool _Geometry::is_polygon_clockwise(const Vector<Vector2> &p_polygon) {
+
+ return Geometry::is_polygon_clockwise(p_polygon);
+}
+
Vector<int> _Geometry::triangulate_polygon(const Vector<Vector2> &p_polygon) {
return Geometry::triangulate_polygon(p_polygon);
}
+Vector<int> _Geometry::triangulate_delaunay_2d(const Vector<Vector2> &p_points) {
+
+ return Geometry::triangulate_delaunay_2d(p_points);
+}
+
Vector<Point2> _Geometry::convex_hull_2d(const Vector<Point2> &p_points) {
return Geometry::convex_hull_2d(p_points);
@@ -1506,6 +1522,107 @@ Vector<Vector3> _Geometry::clip_polygon(const Vector<Vector3> &p_points, const P
return Geometry::clip_polygon(p_points, p_plane);
}
+Array _Geometry::merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+
+ Vector<Vector<Point2> > polys = Geometry::merge_polygons_2d(p_polygon_a, p_polygon_b);
+
+ Array ret;
+
+ for (int i = 0; i < polys.size(); ++i) {
+ ret.push_back(polys[i]);
+ }
+ return ret;
+}
+
+Array _Geometry::clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+
+ Vector<Vector<Point2> > polys = Geometry::clip_polygons_2d(p_polygon_a, p_polygon_b);
+
+ Array ret;
+
+ for (int i = 0; i < polys.size(); ++i) {
+ ret.push_back(polys[i]);
+ }
+ return ret;
+}
+
+Array _Geometry::intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+
+ Vector<Vector<Point2> > polys = Geometry::intersect_polygons_2d(p_polygon_a, p_polygon_b);
+
+ Array ret;
+
+ for (int i = 0; i < polys.size(); ++i) {
+ ret.push_back(polys[i]);
+ }
+ return ret;
+}
+
+Array _Geometry::exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+
+ Vector<Vector<Point2> > polys = Geometry::exclude_polygons_2d(p_polygon_a, p_polygon_b);
+
+ Array ret;
+
+ for (int i = 0; i < polys.size(); ++i) {
+ ret.push_back(polys[i]);
+ }
+ return ret;
+}
+
+Array _Geometry::clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+
+ Vector<Vector<Point2> > polys = Geometry::clip_polyline_with_polygon_2d(p_polyline, p_polygon);
+
+ Array ret;
+
+ for (int i = 0; i < polys.size(); ++i) {
+ ret.push_back(polys[i]);
+ }
+ return ret;
+}
+
+Array _Geometry::intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+
+ Vector<Vector<Point2> > polys = Geometry::intersect_polyline_with_polygon_2d(p_polyline, p_polygon);
+
+ Array ret;
+
+ for (int i = 0; i < polys.size(); ++i) {
+ ret.push_back(polys[i]);
+ }
+ return ret;
+}
+
+Array _Geometry::offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
+
+ Vector<Vector<Point2> > polys = Geometry::offset_polygon_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type));
+
+ Array ret;
+
+ for (int i = 0; i < polys.size(); ++i) {
+ ret.push_back(polys[i]);
+ }
+ return ret;
+}
+
+Array _Geometry::offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
+
+ Vector<Vector<Point2> > polys = Geometry::offset_polyline_2d(p_polygon, p_delta, Geometry::PolyJoinType(p_join_type), Geometry::PolyEndType(p_end_type));
+
+ Array ret;
+
+ for (int i = 0; i < polys.size(); ++i) {
+ ret.push_back(polys[i]);
+ }
+ return ret;
+}
+
+Vector<Point2> _Geometry::transform_points_2d(const Vector<Point2> &p_points, const Transform2D &p_mat) {
+
+ return Geometry::transform_points_2d(p_points, p_mat);
+}
+
Dictionary _Geometry::make_atlas(const Vector<Size2> &p_rects) {
Dictionary ret;
@@ -1566,11 +1683,41 @@ void _Geometry::_bind_methods() {
ClassDB::bind_method(D_METHOD("segment_intersects_convex", "from", "to", "planes"), &_Geometry::segment_intersects_convex);
ClassDB::bind_method(D_METHOD("point_is_inside_triangle", "point", "a", "b", "c"), &_Geometry::point_is_inside_triangle);
+ ClassDB::bind_method(D_METHOD("is_polygon_clockwise", "polygon"), &_Geometry::is_polygon_clockwise);
ClassDB::bind_method(D_METHOD("triangulate_polygon", "polygon"), &_Geometry::triangulate_polygon);
+ ClassDB::bind_method(D_METHOD("triangulate_delaunay_2d", "points"), &_Geometry::triangulate_delaunay_2d);
ClassDB::bind_method(D_METHOD("convex_hull_2d", "points"), &_Geometry::convex_hull_2d);
ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &_Geometry::clip_polygon);
+ ClassDB::bind_method(D_METHOD("merge_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::merge_polygons_2d);
+ ClassDB::bind_method(D_METHOD("clip_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::clip_polygons_2d);
+ ClassDB::bind_method(D_METHOD("intersect_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::intersect_polygons_2d);
+ ClassDB::bind_method(D_METHOD("exclude_polygons_2d", "polygon_a", "polygon_b"), &_Geometry::exclude_polygons_2d);
+
+ ClassDB::bind_method(D_METHOD("clip_polyline_with_polygon_2d", "polyline", "polygon"), &_Geometry::clip_polyline_with_polygon_2d);
+ ClassDB::bind_method(D_METHOD("intersect_polyline_with_polygon_2d", "polyline", "polygon"), &_Geometry::intersect_polyline_with_polygon_2d);
+
+ ClassDB::bind_method(D_METHOD("offset_polygon_2d", "polygon", "delta", "join_type"), &_Geometry::offset_polygon_2d, DEFVAL(JOIN_SQUARE));
+ ClassDB::bind_method(D_METHOD("offset_polyline_2d", "polyline", "delta", "join_type", "end_type"), &_Geometry::offset_polyline_2d, DEFVAL(JOIN_SQUARE), DEFVAL(END_SQUARE));
+
+ ClassDB::bind_method(D_METHOD("transform_points_2d", "points", "transform"), &_Geometry::transform_points_2d);
+
ClassDB::bind_method(D_METHOD("make_atlas", "sizes"), &_Geometry::make_atlas);
+
+ BIND_ENUM_CONSTANT(OPERATION_UNION);
+ BIND_ENUM_CONSTANT(OPERATION_DIFFERENCE);
+ BIND_ENUM_CONSTANT(OPERATION_INTERSECTION);
+ BIND_ENUM_CONSTANT(OPERATION_XOR);
+
+ BIND_ENUM_CONSTANT(JOIN_SQUARE);
+ BIND_ENUM_CONSTANT(JOIN_ROUND);
+ BIND_ENUM_CONSTANT(JOIN_MITER);
+
+ BIND_ENUM_CONSTANT(END_POLYGON);
+ BIND_ENUM_CONSTANT(END_JOINED);
+ BIND_ENUM_CONSTANT(END_BUTT);
+ BIND_ENUM_CONSTANT(END_SQUARE);
+ BIND_ENUM_CONSTANT(END_ROUND);
}
_Geometry::_Geometry() {
@@ -1579,7 +1726,7 @@ _Geometry::_Geometry() {
///////////////////////// FILE
-Error _File::open_encrypted(const String &p_path, int p_mode_flags, const Vector<uint8_t> &p_key) {
+Error _File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
Error err = open(p_path, p_mode_flags);
if (err)
@@ -1596,7 +1743,7 @@ Error _File::open_encrypted(const String &p_path, int p_mode_flags, const Vector
return OK;
}
-Error _File::open_encrypted_pass(const String &p_path, int p_mode_flags, const String &p_pass) {
+Error _File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
Error err = open(p_path, p_mode_flags);
if (err)
@@ -1614,7 +1761,7 @@ Error _File::open_encrypted_pass(const String &p_path, int p_mode_flags, const S
return OK;
}
-Error _File::open_compressed(const String &p_path, int p_mode_flags, int p_compress_mode) {
+Error _File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
FileAccessCompressed *fac = memnew(FileAccessCompressed);
@@ -1631,7 +1778,7 @@ Error _File::open_compressed(const String &p_path, int p_mode_flags, int p_compr
return OK;
}
-Error _File::open(const String &p_path, int p_mode_flags) {
+Error _File::open(const String &p_path, ModeFlags p_mode_flags) {
close();
Error err;
@@ -1908,18 +2055,18 @@ bool _File::file_exists(const String &p_name) const {
return FileAccess::exists(p_name);
}
-void _File::store_var(const Variant &p_var) {
+void _File::store_var(const Variant &p_var, bool p_full_objects) {
ERR_FAIL_COND(!f);
int len;
- Error err = encode_variant(p_var, NULL, len);
+ Error err = encode_variant(p_var, NULL, len, p_full_objects);
ERR_FAIL_COND(err != OK);
PoolVector<uint8_t> buff;
buff.resize(len);
PoolVector<uint8_t>::Write w = buff.write();
- err = encode_variant(p_var, &w[0], len);
+ err = encode_variant(p_var, &w[0], len, p_full_objects);
ERR_FAIL_COND(err != OK);
w = PoolVector<uint8_t>::Write();
@@ -1927,7 +2074,7 @@ void _File::store_var(const Variant &p_var) {
store_buffer(buff);
}
-Variant _File::get_var() const {
+Variant _File::get_var(bool p_allow_objects) const {
ERR_FAIL_COND_V(!f, Variant());
uint32_t len = get_32();
@@ -1937,7 +2084,7 @@ Variant _File::get_var() const {
PoolVector<uint8_t>::Read r = buff.read();
Variant v;
- Error err = decode_variant(v, &r[0], len);
+ Error err = decode_variant(v, &r[0], len, NULL, p_allow_objects);
ERR_FAIL_COND_V(err != OK, Variant());
return v;
@@ -1980,7 +2127,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_endian_swap"), &_File::get_endian_swap);
ClassDB::bind_method(D_METHOD("set_endian_swap", "enable"), &_File::set_endian_swap);
ClassDB::bind_method(D_METHOD("get_error"), &_File::get_error);
- ClassDB::bind_method(D_METHOD("get_var"), &_File::get_var);
+ ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &_File::get_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("store_8", "value"), &_File::store_8);
ClassDB::bind_method(D_METHOD("store_16", "value"), &_File::store_16);
@@ -1993,7 +2140,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("store_line", "line"), &_File::store_line);
ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &_File::store_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("store_string", "string"), &_File::store_string);
- ClassDB::bind_method(D_METHOD("store_var", "value"), &_File::store_var);
+ ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &_File::store_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &_File::store_pascal_string);
ClassDB::bind_method(D_METHOD("get_pascal_string"), &_File::get_pascal_string);
@@ -2223,17 +2370,17 @@ _Marshalls *_Marshalls::get_singleton() {
return singleton;
}
-String _Marshalls::variant_to_base64(const Variant &p_var) {
+String _Marshalls::variant_to_base64(const Variant &p_var, bool p_full_objects) {
int len;
- Error err = encode_variant(p_var, NULL, len);
+ Error err = encode_variant(p_var, NULL, len, p_full_objects);
ERR_FAIL_COND_V(err != OK, "");
PoolVector<uint8_t> buff;
buff.resize(len);
PoolVector<uint8_t>::Write w = buff.write();
- err = encode_variant(p_var, &w[0], len);
+ err = encode_variant(p_var, &w[0], len, p_full_objects);
ERR_FAIL_COND_V(err != OK, "");
int b64len = len / 3 * 4 + 4 + 1;
@@ -2249,7 +2396,7 @@ String _Marshalls::variant_to_base64(const Variant &p_var) {
return ret;
};
-Variant _Marshalls::base64_to_variant(const String &p_str) {
+Variant _Marshalls::base64_to_variant(const String &p_str, bool p_allow_objects) {
int strlen = p_str.length();
CharString cstr = p_str.ascii();
@@ -2261,7 +2408,7 @@ Variant _Marshalls::base64_to_variant(const String &p_str) {
int len = base64_decode((char *)(&w[0]), (char *)cstr.get_data(), strlen);
Variant v;
- Error err = decode_variant(v, &w[0], len);
+ Error err = decode_variant(v, &w[0], len, NULL, p_allow_objects);
ERR_FAIL_COND_V(err != OK, Variant());
return v;
@@ -2340,8 +2487,8 @@ String _Marshalls::base64_to_utf8(const String &p_str) {
void _Marshalls::_bind_methods() {
- ClassDB::bind_method(D_METHOD("variant_to_base64", "variant"), &_Marshalls::variant_to_base64);
- ClassDB::bind_method(D_METHOD("base64_to_variant", "base64_str"), &_Marshalls::base64_to_variant);
+ ClassDB::bind_method(D_METHOD("variant_to_base64", "variant", "full_objects"), &_Marshalls::variant_to_base64, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("base64_to_variant", "base64_str", "allow_objects"), &_Marshalls::base64_to_variant, DEFVAL(false));
ClassDB::bind_method(D_METHOD("raw_to_base64", "array"), &_Marshalls::raw_to_base64);
ClassDB::bind_method(D_METHOD("base64_to_raw", "base64_str"), &_Marshalls::base64_to_raw);
@@ -2445,7 +2592,8 @@ void _Thread::_start_func(void *ud) {
reason = "Method Not Found";
} break;
- default: {}
+ default: {
+ }
}
ERR_EXPLAIN("Could not call function '" + t->target_method.operator String() + "'' starting thread ID: " + t->get_id() + " Reason: " + reason);
@@ -2453,12 +2601,12 @@ void _Thread::_start_func(void *ud) {
}
}
-Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, int p_priority) {
+Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) {
ERR_FAIL_COND_V(active, ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER);
- ERR_FAIL_INDEX_V(p_priority, 3, ERR_INVALID_PARAMETER);
+ ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER);
ret = Variant();
target_method = p_method;
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 803743bc93..8f74d88be5 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -85,7 +85,7 @@ public:
static _ResourceSaver *get_singleton() { return singleton; }
- Error save(const String &p_path, const RES &p_resource, uint32_t p_flags);
+ Error save(const String &p_path, const RES &p_resource, SaverFlags p_flags);
PoolVector<String> get_recognized_extensions(const RES &p_resource);
_ResourceSaver();
@@ -214,7 +214,7 @@ public:
bool is_in_low_processor_usage_mode() const;
String get_executable_path() const;
- int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output = Array());
+ int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output = Array(), bool p_read_stderr = false);
Error kill(int p_pid);
Error shell_open(String p_uri);
@@ -275,6 +275,7 @@ public:
void set_use_file_access_save_and_swap(bool p_enable);
+ void set_native_icon(const String &p_filename);
void set_icon(const Ref<Image> &p_icon);
int get_exit_code() const;
@@ -402,15 +403,55 @@ public:
real_t segment_intersects_circle(const Vector2 &p_from, const Vector2 &p_to, const Vector2 &p_circle_pos, real_t p_circle_radius);
int get_uv84_normal_bit(const Vector3 &p_vector);
+ bool is_polygon_clockwise(const Vector<Vector2> &p_polygon);
Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon);
+ Vector<int> triangulate_delaunay_2d(const Vector<Vector2> &p_points);
Vector<Point2> convex_hull_2d(const Vector<Point2> &p_points);
Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane);
+ enum PolyBooleanOperation {
+ OPERATION_UNION,
+ OPERATION_DIFFERENCE,
+ OPERATION_INTERSECTION,
+ OPERATION_XOR
+ };
+ // 2D polygon boolean operations
+ Array merge_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // union (add)
+ Array clip_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // difference (subtract)
+ Array intersect_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // common area (multiply)
+ Array exclude_polygons_2d(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // all but common area (xor)
+
+ // 2D polyline vs polygon operations
+ Array clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // cut
+ Array intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // chop
+
+ // 2D offset polygons/polylines
+ enum PolyJoinType {
+ JOIN_SQUARE,
+ JOIN_ROUND,
+ JOIN_MITER
+ };
+ enum PolyEndType {
+ END_POLYGON,
+ END_JOINED,
+ END_BUTT,
+ END_SQUARE,
+ END_ROUND
+ };
+ Array offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE);
+ Array offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE);
+
+ Vector<Point2> transform_points_2d(const Vector<Point2> &p_points, const Transform2D &p_mat);
+
Dictionary make_atlas(const Vector<Size2> &p_rects);
_Geometry();
};
+VARIANT_ENUM_CAST(_Geometry::PolyBooleanOperation);
+VARIANT_ENUM_CAST(_Geometry::PolyJoinType);
+VARIANT_ENUM_CAST(_Geometry::PolyEndType);
+
class _File : public Reference {
GDCLASS(_File, Reference);
@@ -436,11 +477,11 @@ public:
COMPRESSION_GZIP = Compression::MODE_GZIP
};
- Error open_encrypted(const String &p_path, int p_mode_flags, const Vector<uint8_t> &p_key);
- Error open_encrypted_pass(const String &p_path, int p_mode_flags, const String &p_pass);
- Error open_compressed(const String &p_path, int p_mode_flags, int p_compress_mode = 0);
+ Error open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
+ Error open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
+ Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
- Error open(const String &p_path, int p_mode_flags); ///< open a file
+ Error open(const String &p_path, ModeFlags p_mode_flags); ///< open a file
void close(); ///< close a file
bool is_open() const; ///< true when file is open
@@ -463,7 +504,7 @@ public:
double get_double() const;
real_t get_real() const;
- Variant get_var() const;
+ Variant get_var(bool p_allow_objects = false) const;
PoolVector<uint8_t> get_buffer(int p_length) const; ///< get an array of bytes
String get_line() const;
@@ -500,7 +541,7 @@ public:
void store_buffer(const PoolVector<uint8_t> &p_buffer); ///< store an array of bytes
- void store_var(const Variant &p_var);
+ void store_var(const Variant &p_var, bool p_full_objects = false);
bool file_exists(const String &p_name) const; ///< return true if a file exists
@@ -569,8 +610,8 @@ protected:
public:
static _Marshalls *get_singleton();
- String variant_to_base64(const Variant &p_var);
- Variant base64_to_variant(const String &p_str);
+ String variant_to_base64(const Variant &p_var, bool p_full_objects = false);
+ Variant base64_to_variant(const String &p_str, bool p_allow_objects = false);
String raw_to_base64(const PoolVector<uint8_t> &p_arr);
PoolVector<uint8_t> base64_to_raw(const String &p_str);
@@ -632,10 +673,11 @@ public:
PRIORITY_LOW,
PRIORITY_NORMAL,
- PRIORITY_HIGH
+ PRIORITY_HIGH,
+ PRIORITY_MAX
};
- Error start(Object *p_instance, const StringName &p_method, const Variant &p_userdata = Variant(), int p_priority = PRIORITY_NORMAL);
+ Error start(Object *p_instance, const StringName &p_method, const Variant &p_userdata = Variant(), Priority p_priority = PRIORITY_NORMAL);
String get_id() const;
bool is_active() const;
Variant wait_to_finish();
diff --git a/core/class_db.cpp b/core/class_db.cpp
index 219bdbddd8..0c844657a4 100644
--- a/core/class_db.cpp
+++ b/core/class_db.cpp
@@ -249,6 +249,11 @@ void ClassDB::set_current_api(APIType p_api) {
current_api = p_api;
}
+ClassDB::APIType ClassDB::get_current_api() {
+
+ return current_api;
+}
+
HashMap<StringName, ClassDB::ClassInfo> ClassDB::classes;
HashMap<StringName, StringName> ClassDB::resource_base_extensions;
HashMap<StringName, StringName> ClassDB::compat_classes;
@@ -307,6 +312,19 @@ void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringNa
}
}
+void ClassDB::get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
+
+ OBJTYPE_RLOCK;
+
+ const StringName *k = NULL;
+
+ while ((k = classes.next(k))) {
+
+ if (*k != p_class && get_parent_class(*k) == p_class)
+ p_classes->push_back(*k);
+ }
+}
+
StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) {
OBJTYPE_RLOCK;
diff --git a/core/class_db.h b/core/class_db.h
index 321682d76b..efa1a46866 100644
--- a/core/class_db.h
+++ b/core/class_db.h
@@ -214,6 +214,7 @@ public:
static void get_class_list(List<StringName> *p_classes);
static void get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
+ static void get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
static StringName get_parent_class_nocheck(const StringName &p_class);
static StringName get_parent_class(const StringName &p_class);
static bool class_exists(const StringName &p_class);
@@ -371,6 +372,7 @@ public:
static void init();
static void set_current_api(APIType p_api);
+ static APIType get_current_api();
static void cleanup();
};
diff --git a/core/color_names.inc b/core/color_names.inc
index e126bfe0f8..b0ef507d92 100644
--- a/core/color_names.inc
+++ b/core/color_names.inc
@@ -143,6 +143,7 @@ static void _populate_named_colors() {
_named_colors.insert("thistle", Color(0.85, 0.75, 0.85));
_named_colors.insert("tomato", Color(1.00, 0.39, 0.28));
_named_colors.insert("turquoise", Color(0.25, 0.88, 0.82));
+ _named_colors.insert("transparent", Color(1.00, 1.00, 1.00, 0.00));
_named_colors.insert("violet", Color(0.93, 0.51, 0.93));
_named_colors.insert("wheat", Color(0.96, 0.87, 0.70));
_named_colors.insert("white", Color(1.00, 1.00, 1.00));
diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h
index 59eabd8786..798fa4394d 100644
--- a/core/command_queue_mt.h
+++ b/core/command_queue_mt.h
@@ -406,8 +406,10 @@ class CommandQueueMT {
tryagain:
// tried to read an empty queue
- if (read_ptr == write_ptr)
+ if (read_ptr == write_ptr) {
+ if (p_lock) unlock();
return false;
+ }
uint32_t size_ptr = read_ptr;
uint32_t size = *(uint32_t *)&command_mem[read_ptr] >> 1;
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index 1b59508abf..eeaae96754 100644
--- a/core/core_string_names.cpp
+++ b/core/core_string_names.cpp
@@ -44,6 +44,7 @@ CoreStringNames::CoreStringNames() :
_iter_next(StaticCString::create("_iter_next")),
_iter_get(StaticCString::create("_iter_get")),
get_rid(StaticCString::create("get_rid")),
+ _to_string(StaticCString::create("_to_string")),
#ifdef TOOLS_ENABLED
_sections_unfolded(StaticCString::create("_sections_unfolded")),
#endif
diff --git a/core/core_string_names.h b/core/core_string_names.h
index 6fea40e1b2..85f8bb7f62 100644
--- a/core/core_string_names.h
+++ b/core/core_string_names.h
@@ -62,6 +62,7 @@ public:
StringName _iter_next;
StringName _iter_get;
StringName get_rid;
+ StringName _to_string;
#ifdef TOOLS_ENABLED
StringName _sections_unfolded;
#endif
diff --git a/core/dictionary.cpp b/core/dictionary.cpp
index bea0997cc9..5e4dfb9a5a 100644
--- a/core/dictionary.cpp
+++ b/core/dictionary.cpp
@@ -270,6 +270,10 @@ void Dictionary::operator=(const Dictionary &p_dictionary) {
_ref(p_dictionary);
}
+const void *Dictionary::id() const {
+ return _p->variant_map.id();
+}
+
Dictionary::Dictionary(const Dictionary &p_from) {
_p = NULL;
_ref(p_from);
diff --git a/core/dictionary.h b/core/dictionary.h
index eab7354cef..b68d3f5737 100644
--- a/core/dictionary.h
+++ b/core/dictionary.h
@@ -82,6 +82,8 @@ public:
Dictionary duplicate(bool p_deep = false) const;
+ const void *id() const;
+
Dictionary(const Dictionary &p_from);
Dictionary();
~Dictionary();
diff --git a/core/error_macros.h b/core/error_macros.h
index ca5ccd24cf..f72e987e23 100644
--- a/core/error_macros.h
+++ b/core/error_macros.h
@@ -41,7 +41,7 @@
*/
/**
- * Pointer to the error macro priting function. Reassign to any function to have errors printed
+ * Pointer to the error macro printing function. Reassign to any function to have errors printed
*/
/** Function used by the error macros */
@@ -86,7 +86,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
#define _FNL __FILE__ ":"
-/** An index has failed if m_index<0 or m_index >=m_size, the function exists */
+/** An index has failed if m_index<0 or m_index >=m_size, the function exits */
extern bool _err_error_exists;
@@ -140,7 +140,7 @@ extern bool _err_error_exists;
_err_error_exists = false; \
} while (0); // (*)
-/** An index has failed if m_index<0 or m_index >=m_size, the function exists.
+/** An index has failed if m_index<0 or m_index >=m_size, the function exits.
* This function returns an error value, if returning Error, please select the most
* appropriate error condition from error_macros.h
*/
@@ -154,7 +154,7 @@ extern bool _err_error_exists;
_err_error_exists = false; \
} while (0); // (*)
-/** An index has failed if m_index >=m_size, the function exists.
+/** An index has failed if m_index >=m_size, the function exits.
* This function returns an error value, if returning Error, please select the most
* appropriate error condition from error_macros.h
*/
diff --git a/core/func_ref.cpp b/core/func_ref.cpp
index 4a965473d9..3d03137d09 100644
--- a/core/func_ref.cpp
+++ b/core/func_ref.cpp
@@ -51,11 +51,23 @@ void FuncRef::set_instance(Object *p_obj) {
ERR_FAIL_NULL(p_obj);
id = p_obj->get_instance_id();
}
+
void FuncRef::set_function(const StringName &p_func) {
function = p_func;
}
+bool FuncRef::is_valid() const {
+ if (id == 0)
+ return false;
+
+ Object *obj = ObjectDB::get_instance(id);
+ if (!obj)
+ return false;
+
+ return obj->has_method(function);
+}
+
void FuncRef::_bind_methods() {
{
@@ -67,6 +79,7 @@ void FuncRef::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_instance", "instance"), &FuncRef::set_instance);
ClassDB::bind_method(D_METHOD("set_function", "name"), &FuncRef::set_function);
+ ClassDB::bind_method(D_METHOD("is_valid"), &FuncRef::is_valid);
}
FuncRef::FuncRef() :
diff --git a/core/func_ref.h b/core/func_ref.h
index 339279fdba..a143b58bf0 100644
--- a/core/func_ref.h
+++ b/core/func_ref.h
@@ -46,6 +46,7 @@ public:
Variant call_func(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
void set_instance(Object *p_obj);
void set_function(const StringName &p_func);
+ bool is_valid() const;
FuncRef();
};
diff --git a/core/image.cpp b/core/image.cpp
index f547d7e973..30af724de9 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -725,6 +725,131 @@ static void _scale_nearest(const uint8_t *__restrict p_src, uint8_t *__restrict
}
}
+#define LANCZOS_TYPE 3
+
+static float _lanczos(float p_x) {
+ return Math::abs(p_x) >= LANCZOS_TYPE ? 0 : Math::sincn(p_x) * Math::sincn(p_x / LANCZOS_TYPE);
+}
+
+template <int CC, class T>
+static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
+
+ int32_t src_width = p_src_width;
+ int32_t src_height = p_src_height;
+ int32_t dst_height = p_dst_height;
+ int32_t dst_width = p_dst_width;
+
+ uint32_t buffer_size = src_height * dst_width * CC;
+ float *buffer = memnew_arr(float, buffer_size); // Store the first pass in a buffer
+
+ { // FIRST PASS (horizontal)
+
+ float x_scale = float(src_width) / float(dst_width);
+
+ float scale_factor = MAX(x_scale, 1); // A larger kernel is required only when downscaling
+ int32_t half_kernel = LANCZOS_TYPE * scale_factor;
+
+ float *kernel = memnew_arr(float, half_kernel * 2 - 1);
+
+ for (int32_t buffer_x = 0; buffer_x < dst_width; buffer_x++) {
+
+ float src_real_x = buffer_x * x_scale;
+ int32_t src_x = src_real_x;
+
+ int32_t start_x = MAX(0, src_x - half_kernel + 1);
+ int32_t end_x = MIN(src_width - 1, src_x + half_kernel);
+
+ // Create the kernel used by all the pixels of the column
+ for (int32_t target_x = start_x; target_x <= end_x; target_x++)
+ kernel[target_x - start_x] = _lanczos((src_real_x - target_x) / scale_factor);
+
+ for (int32_t buffer_y = 0; buffer_y < src_height; buffer_y++) {
+
+ float pixel[CC] = { 0 };
+ float weight = 0;
+
+ for (int32_t target_x = start_x; target_x <= end_x; target_x++) {
+
+ float lanczos_val = kernel[target_x - start_x];
+ weight += lanczos_val;
+
+ const T *__restrict src_data = ((const T *)p_src) + (buffer_y * src_width + target_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++) {
+ if (sizeof(T) == 2) //half float
+ pixel[i] += Math::half_to_float(src_data[i]) * lanczos_val;
+ else
+ pixel[i] += src_data[i] * lanczos_val;
+ }
+ }
+
+ float *dst_data = ((float *)buffer) + (buffer_y * dst_width + buffer_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++)
+ dst_data[i] = pixel[i] / weight; // Normalize the sum of all the samples
+ }
+ }
+
+ memdelete_arr(kernel);
+ } // End of first pass
+
+ { // SECOND PASS (vertical + result)
+
+ float y_scale = float(src_height) / float(dst_height);
+
+ float scale_factor = MAX(y_scale, 1);
+ int32_t half_kernel = LANCZOS_TYPE * scale_factor;
+
+ float *kernel = memnew_arr(float, half_kernel * 2 - 1);
+
+ for (int32_t dst_y = 0; dst_y < dst_height; dst_y++) {
+
+ float buffer_real_y = dst_y * y_scale;
+ int32_t buffer_y = buffer_real_y;
+
+ int32_t start_y = MAX(0, buffer_y - half_kernel + 1);
+ int32_t end_y = MIN(src_height - 1, buffer_y + half_kernel);
+
+ for (int32_t target_y = start_y; target_y <= end_y; target_y++)
+ kernel[target_y - start_y] = _lanczos((buffer_real_y - target_y) / scale_factor);
+
+ for (int32_t dst_x = 0; dst_x < dst_width; dst_x++) {
+
+ float pixel[CC] = { 0 };
+ float weight = 0;
+
+ for (int32_t target_y = start_y; target_y <= end_y; target_y++) {
+
+ float lanczos_val = kernel[target_y - start_y];
+ weight += lanczos_val;
+
+ float *buffer_data = ((float *)buffer) + (target_y * dst_width + dst_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++)
+ pixel[i] += buffer_data[i] * lanczos_val;
+ }
+
+ T *dst_data = ((T *)p_dst) + (dst_y * dst_width + dst_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++) {
+ pixel[i] /= weight;
+
+ if (sizeof(T) == 1) //byte
+ dst_data[i] = CLAMP(Math::fast_ftoi(pixel[i]), 0, 255);
+ else if (sizeof(T) == 2) //half float
+ dst_data[i] = Math::make_half_float(pixel[i]);
+ else // float
+ dst_data[i] = pixel[i];
+ }
+ }
+ }
+
+ memdelete_arr(kernel);
+ } // End of second pass
+
+ memdelete_arr(buffer);
+}
+
static void _overlay(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, float p_alpha, uint32_t p_width, uint32_t p_height, uint32_t p_pixel_size) {
uint16_t alpha = CLAMP((uint16_t)(p_alpha * 256.0f), 0, 256);
@@ -939,6 +1064,31 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
}
}
} break;
+ case INTERPOLATE_LANCZOS: {
+
+ if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
+ switch (get_format_pixel_size(format)) {
+ case 1: _scale_lanczos<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 2: _scale_lanczos<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 3: _scale_lanczos<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 4: _scale_lanczos<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ }
+ } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
+ switch (get_format_pixel_size(format)) {
+ case 4: _scale_lanczos<1, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 8: _scale_lanczos<2, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 12: _scale_lanczos<3, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 16: _scale_lanczos<4, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ }
+ } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
+ switch (get_format_pixel_size(format)) {
+ case 2: _scale_lanczos<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 4: _scale_lanczos<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 6: _scale_lanczos<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 8: _scale_lanczos<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ }
+ }
+ } break;
}
r = PoolVector<uint8_t>::Read();
@@ -1266,7 +1416,8 @@ void Image::shrink_x2() {
case FORMAT_RGBAH: _generate_po2_mipmap<uint16_t, 4, false, Image::average_4_half, Image::renormalize_half>(reinterpret_cast<const uint16_t *>(r.ptr()), reinterpret_cast<uint16_t *>(w.ptr()), width, height); break;
case FORMAT_RGBE9995: _generate_po2_mipmap<uint32_t, 1, false, Image::average_4_rgbe9995, Image::renormalize_rgbe9995>(reinterpret_cast<const uint32_t *>(r.ptr()), reinterpret_cast<uint32_t *>(w.ptr()), width, height); break;
- default: {}
+ default: {
+ }
}
}
@@ -1398,7 +1549,8 @@ Error Image::generate_mipmaps(bool p_renormalize) {
_generate_po2_mipmap<uint32_t, 1, false, Image::average_4_rgbe9995, Image::renormalize_rgbe9995>(reinterpret_cast<const uint32_t *>(&wp[prev_ofs]), reinterpret_cast<uint32_t *>(&wp[ofs]), prev_w, prev_h);
break;
- default: {}
+ default: {
+ }
}
prev_ofs = ofs;
@@ -1612,7 +1764,8 @@ void Image::create(const char **p_xpm) {
if (y == (size_height - 1))
status = DONE;
} break;
- default: {}
+ default: {
+ }
}
line++;
@@ -1685,7 +1838,8 @@ bool Image::is_invisible() const {
case FORMAT_DXT5: {
detected = true;
} break;
- default: {}
+ default: {
+ }
}
return !detected;
@@ -1729,7 +1883,8 @@ Image::AlphaMode Image::detect_alpha() const {
case FORMAT_DXT5: {
detected = true;
} break;
- default: {}
+ default: {
+ }
}
if (detected)
@@ -1871,7 +2026,7 @@ Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const P
Rect2 Image::get_used_rect() const {
- if (format != FORMAT_LA8 && format != FORMAT_RGBA8)
+ if (format != FORMAT_LA8 && format != FORMAT_RGBA8 && format != FORMAT_RGBAF && format != FORMAT_RGBAH && format != FORMAT_RGBA4444 && format != FORMAT_RGBA5551)
return Rect2(Point2(), Size2(width, height));
int len = data.size();
@@ -1879,17 +2034,13 @@ Rect2 Image::get_used_rect() const {
if (len == 0)
return Rect2();
- //int data_size = len;
- PoolVector<uint8_t>::Read r = data.read();
- const unsigned char *rptr = r.ptr();
-
- int ps = format == FORMAT_LA8 ? 2 : 4;
+ const_cast<Image *>(this)->lock();
int minx = 0xFFFFFF, miny = 0xFFFFFFF;
int maxx = -1, maxy = -1;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
- bool opaque = rptr[(j * width + i) * ps + (ps - 1)] > 2;
+ bool opaque = get_pixel(i, j).a > 0.99;
if (!opaque)
continue;
if (i > maxx)
@@ -1903,6 +2054,8 @@ Rect2 Image::get_used_rect() const {
}
}
+ const_cast<Image *>(this)->unlock();
+
if (maxx == -1)
return Rect2();
else
@@ -2682,6 +2835,7 @@ void Image::_bind_methods() {
BIND_ENUM_CONSTANT(INTERPOLATE_BILINEAR);
BIND_ENUM_CONSTANT(INTERPOLATE_CUBIC);
BIND_ENUM_CONSTANT(INTERPOLATE_TRILINEAR);
+ BIND_ENUM_CONSTANT(INTERPOLATE_LANCZOS);
BIND_ENUM_CONSTANT(ALPHA_NONE);
BIND_ENUM_CONSTANT(ALPHA_BIT);
diff --git a/core/image.h b/core/image.h
index 69a42f169a..752ef20208 100644
--- a/core/image.h
+++ b/core/image.h
@@ -109,6 +109,7 @@ public:
INTERPOLATE_BILINEAR,
INTERPOLATE_CUBIC,
INTERPOLATE_TRILINEAR,
+ INTERPOLATE_LANCZOS,
/* INTERPOLATE_TRICUBIC, */
/* INTERPOLATE GAUSS */
};
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index a113f3b61b..b51e50150e 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -175,7 +175,9 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p
} break;
case MODE_ZSTD: {
ZSTD_DCtx *dctx = ZSTD_createDCtx();
- if (zstd_long_distance_matching) ZSTD_DCtx_setMaxWindowSize(dctx, (size_t)1 << zstd_window_log_size);
+ if (zstd_long_distance_matching) {
+ ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, zstd_window_log_size);
+ }
int ret = ZSTD_decompressDCtx(dctx, p_dst, p_dst_max_size, p_src, p_src_size);
ZSTD_freeDCtx(dctx);
return ret;
@@ -189,4 +191,4 @@ int Compression::zlib_level = Z_DEFAULT_COMPRESSION;
int Compression::gzip_level = Z_DEFAULT_COMPRESSION;
int Compression::zstd_level = 3;
bool Compression::zstd_long_distance_matching = false;
-int Compression::zstd_window_log_size = 27;
+int Compression::zstd_window_log_size = 27; // ZSTD_WINDOWLOG_LIMIT_DEFAULT
diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h
index be960fbc25..24b40cbce8 100644
--- a/core/io/file_access_buffered_fa.h
+++ b/core/io/file_access_buffered_fa.h
@@ -143,6 +143,14 @@ public:
return f._get_modified_time(p_file);
}
+ virtual uint32_t _get_unix_permissions(const String &p_file) {
+ return f._get_unix_permissions(p_file);
+ }
+
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+ return f._set_unix_permissions(p_file, p_permissions);
+ }
+
FileAccessBufferedFA(){
};
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index b268d5c710..6c4310a572 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -373,6 +373,19 @@ uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) {
return 0;
}
+uint32_t FileAccessCompressed::_get_unix_permissions(const String &p_file) {
+ if (f)
+ return f->_get_unix_permissions(p_file);
+ return 0;
+}
+
+Error FileAccessCompressed::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+ if (f) {
+ return f->_set_unix_permissions(p_file, p_permissions);
+ }
+ return FAILED;
+}
+
FileAccessCompressed::FileAccessCompressed() :
cmode(Compression::MODE_ZSTD),
writing(false),
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index f408b1bc29..773fed6a3a 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -91,6 +91,8 @@ public:
virtual bool file_exists(const String &p_name); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file);
+ virtual uint32_t _get_unix_permissions(const String &p_file);
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
FileAccessCompressed();
virtual ~FileAccessCompressed();
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 6ad68dd74d..3ff9fa569c 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -100,6 +100,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8
MD5Update(&md5, (uint8_t *)data.ptr(), data.size());
MD5Final(&md5);
+ ERR_EXPLAIN("The MD5 sum of the decrypted file does not match the expected value. It could be that the file is corrupt, or that the provided decryption key is invalid.");
ERR_FAIL_COND_V(String::md5(md5.digest) != String::md5(md5d), ERR_FILE_CORRUPT);
file = p_base;
@@ -301,6 +302,16 @@ uint64_t FileAccessEncrypted::_get_modified_time(const String &p_file) {
return 0;
}
+uint32_t FileAccessEncrypted::_get_unix_permissions(const String &p_file) {
+
+ return 0;
+}
+
+Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+
+ return FAILED;
+}
+
FileAccessEncrypted::FileAccessEncrypted() {
file = NULL;
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index e77d62a9f4..d779a150ac 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -79,6 +79,8 @@ public:
virtual bool file_exists(const String &p_name); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file);
+ virtual uint32_t _get_unix_permissions(const String &p_file);
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
FileAccessEncrypted();
~FileAccessEncrypted();
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 73952133c1..4db7811aaa 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -70,6 +70,8 @@ public:
virtual bool file_exists(const String &p_name); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
FileAccessMemory();
};
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 501a21a50d..2572602e16 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -118,7 +118,10 @@ void FileAccessNetworkClient::_thread_func() {
FileAccessNetwork *fa = NULL;
if (response != FileAccessNetwork::RESPONSE_DATA) {
- ERR_FAIL_COND(!accesses.has(id));
+ if (!accesses.has(id)) {
+ unlock_mutex();
+ ERR_FAIL_COND(!accesses.has(id));
+ }
}
if (accesses.has(id))
@@ -497,6 +500,16 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) {
return exists_modtime;
}
+uint32_t FileAccessNetwork::_get_unix_permissions(const String &p_file) {
+ //could be implemented, not sure if worth it
+ return 0;
+}
+
+Error FileAccessNetwork::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+
+ return FAILED;
+}
+
void FileAccessNetwork::configure() {
GLOBAL_DEF("network/remote_fs/page_size", 65536);
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index 5bbf7588c7..073b75a37b 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -159,6 +159,8 @@ public:
virtual bool file_exists(const String &p_path); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file);
+ virtual uint32_t _get_unix_permissions(const String &p_file);
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
static void configure();
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index c97b8cafac..d38d09c6bb 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -272,7 +272,7 @@ int FileAccessPack::get_buffer(uint8_t *p_dst, int p_length) const {
if (eof)
return 0;
- int64_t to_read = p_length;
+ uint64_t to_read = p_length;
if (to_read + pos > pf.size) {
eof = true;
to_read = int64_t(pf.size) - int64_t(pos);
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index a90672ce26..a21dd7d22d 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -142,6 +142,8 @@ class FileAccessPack : public FileAccess {
FileAccess *f;
virtual Error _open(const String &p_path, int p_mode_flags);
virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
public:
virtual void close();
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index fc8f85c07b..217176c0af 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -112,6 +112,8 @@ public:
virtual bool file_exists(const String &p_name); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) { return 0; } // todo
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
FileAccessZip(const String &p_path, const PackedData::PackedFile &p_file);
~FileAccessZip();
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index e5c6d2a4f2..ce2054db36 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -429,7 +429,7 @@ Error HTTPClient::poll() {
response_num = RESPONSE_OK;
// Per the HTTP 1.1 spec, keep-alive is the default.
- // Not following that specification breaks standard implemetations.
+ // Not following that specification breaks standard implementations.
// Broken web servers should be fixed.
bool keep_alive = true;
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index a5a0738140..a759e615c7 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -65,6 +65,9 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_c
if (!loader[i]->recognize(extension))
continue;
Error err = loader[i]->load_image(p_image, f, p_force_linear, p_scale);
+ if (err != OK) {
+ ERR_PRINTS("Error loading image: " + p_file);
+ }
if (err != ERR_FILE_UNRECOGNIZED) {
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index 5087a63b68..d1b6b82cf0 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -768,7 +768,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
r_variant = carray;
} break;
- default: { ERR_FAIL_V(ERR_BUG); }
+ default: {
+ ERR_FAIL_V(ERR_BUG);
+ }
}
return OK;
@@ -794,7 +796,7 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) {
}
}
-Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_object_as_id) {
+Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects) {
uint8_t *buf = r_buffer;
@@ -819,11 +821,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
} break;
case Variant::OBJECT: {
- if (p_object_as_id) {
+ if (!p_full_objects) {
flags |= ENCODE_FLAG_OBJECT_AS_ID;
}
} break;
- default: {} // nothing to do at this stage
+ default: {
+ } // nothing to do at this stage
}
if (buf) {
@@ -1086,22 +1089,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
} break;
case Variant::OBJECT: {
- if (p_object_as_id) {
-
- if (buf) {
-
- Object *obj = p_variant;
- ObjectID id = 0;
- if (obj && ObjectDB::instance_validate(obj)) {
- id = obj->get_instance_id();
- }
-
- encode_uint64(id, buf);
- }
-
- r_len += 8;
+ if (p_full_objects) {
- } else {
Object *obj = p_variant;
if (!obj) {
if (buf) {
@@ -1139,7 +1128,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
_encode_string(E->get().name, buf, r_len);
int len;
- Error err = encode_variant(obj->get(E->get().name), buf, len, p_object_as_id);
+ Error err = encode_variant(obj->get(E->get().name), buf, len, p_full_objects);
if (err)
return err;
ERR_FAIL_COND_V(len % 4, ERR_BUG);
@@ -1148,6 +1137,19 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
buf += len;
}
}
+ } else {
+ if (buf) {
+
+ Object *obj = p_variant;
+ ObjectID id = 0;
+ if (obj && ObjectDB::instance_validate(obj)) {
+ id = obj->get_instance_id();
+ }
+
+ encode_uint64(id, buf);
+ }
+
+ r_len += 8;
}
} break;
@@ -1180,14 +1182,14 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len++; //pad
*/
int len;
- encode_variant(E->get(), buf, len, p_object_as_id);
+ encode_variant(E->get(), buf, len, p_full_objects);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf)
buf += len;
Variant *v = d.getptr(E->get());
ERR_FAIL_COND_V(!v, ERR_BUG);
- encode_variant(*v, buf, len, p_object_as_id);
+ encode_variant(*v, buf, len, p_full_objects);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf)
@@ -1209,7 +1211,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
for (int i = 0; i < v.size(); i++) {
int len;
- encode_variant(v.get(i), buf, len, p_object_as_id);
+ encode_variant(v.get(i), buf, len, p_full_objects);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf)
@@ -1229,11 +1231,15 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
buf += 4;
PoolVector<uint8_t>::Read r = data.read();
copymem(buf, &r[0], datalen * datasize);
+ buf += datalen * datasize;
}
r_len += 4 + datalen * datasize;
- while (r_len % 4)
+ while (r_len % 4) {
r_len++;
+ if (buf)
+ *(buf++) = 0;
+ }
} break;
case Variant::POOL_INT_ARRAY: {
@@ -1386,7 +1392,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len += 4 * 4 * len;
} break;
- default: { ERR_FAIL_V(ERR_BUG); }
+ default: {
+ ERR_FAIL_V(ERR_BUG);
+ }
}
return OK;
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index 11c4b2c98e..f361c29754 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -199,7 +199,7 @@ public:
EncodedObjectAsID();
};
-Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects = true);
-Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_object_as_id = false);
+Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects = false);
+Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false);
#endif
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 7680d47620..2779837190 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -46,7 +46,8 @@ _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_mas
case MultiplayerAPI::RPC_MODE_MASTERSYNC: {
if (is_master)
r_skip_rpc = true; // I am the master, so skip remote call.
- } // Do not break, fall over to other sync.
+ FALLTHROUGH;
+ }
case MultiplayerAPI::RPC_MODE_REMOTESYNC:
case MultiplayerAPI::RPC_MODE_PUPPETSYNC: {
// Call it, sync always results in a local call.
@@ -282,8 +283,9 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name);
}
- ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
- ERR_FAIL_COND(!_can_call_mode(p_node, rpc_mode, p_from));
+ bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
+ ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
+ ERR_FAIL_COND(!can_call);
int argc = p_packet[p_offset];
Vector<Variant> args;
@@ -299,7 +301,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
ERR_FAIL_COND(p_offset >= p_packet_len);
int vlen;
- Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen);
+ Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Invalid packet received. Unable to decode RPC argument.");
ERR_FAIL_COND(err != OK);
@@ -331,11 +333,12 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p
rset_mode = p_node->get_script_instance()->get_rset_mode(p_name);
}
- ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
- ERR_FAIL_COND(!_can_call_mode(p_node, rset_mode, p_from));
+ bool can_call = _can_call_mode(p_node, rset_mode, p_from);
+ ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
+ ERR_FAIL_COND(!can_call);
Variant value;
- Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset);
+ Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Invalid packet received. Unable to decode RSET value.");
ERR_FAIL_COND(err != OK);
@@ -526,11 +529,11 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
if (p_set) {
// Set argument.
- Error err = encode_variant(*p_arg[0], NULL, len);
+ Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!");
ERR_FAIL_COND(err != OK);
MAKE_ROOM(ofs + len);
- encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len);
+ encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ofs += len;
} else {
@@ -539,11 +542,11 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
packet_cache.write[ofs] = p_argcount;
ofs += 1;
for (int i = 0; i < p_argcount; i++) {
- Error err = encode_variant(*p_arg[i], NULL, len);
+ Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!");
ERR_FAIL_COND(err != OK);
MAKE_ROOM(ofs + len);
- encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len);
+ encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed());
ofs += len;
}
}
@@ -631,7 +634,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED);
int node_id = network_peer->get_unique_id();
- bool skip_rpc = false;
+ bool skip_rpc = node_id == p_peer_id;
bool call_local_native = false;
bool call_local_script = false;
bool is_master = p_node->is_network_master();
@@ -658,8 +661,11 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
if (call_local_native) {
+ int temp_id = rpc_sender_id;
+ rpc_sender_id = get_network_unique_id();
Variant::CallError ce;
p_node->call(p_method, p_arg, p_argcount, ce);
+ rpc_sender_id = temp_id;
if (ce.error != Variant::CallError::CALL_OK) {
String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce);
error = "rpc() aborted in local call: - " + error;
@@ -669,9 +675,12 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
if (call_local_script) {
+ int temp_id = rpc_sender_id;
+ rpc_sender_id = get_network_unique_id();
Variant::CallError ce;
ce.error = Variant::CallError::CALL_OK;
p_node->get_script_instance()->call(p_method, p_arg, p_argcount, ce);
+ rpc_sender_id = temp_id;
if (ce.error != Variant::CallError::CALL_OK) {
String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce);
error = "rpc() aborted in script local call: - " + error;
@@ -679,6 +688,9 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
return;
}
}
+
+ ERR_EXPLAIN("RPC '" + p_method + "' on yourself is not allowed by selected mode");
+ ERR_FAIL_COND(skip_rpc && !(call_local_native || call_local_script));
}
void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
@@ -692,13 +704,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
int node_id = network_peer->get_unique_id();
bool is_master = p_node->is_network_master();
- bool skip_rset = false;
+ bool skip_rset = node_id == p_peer_id;
+ bool set_local = false;
if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) {
// Check that send mode can use local call.
-
- bool set_local = false;
-
const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_property);
if (E) {
@@ -707,7 +717,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (set_local) {
bool valid;
+ int temp_id = rpc_sender_id;
+
+ rpc_sender_id = get_network_unique_id();
p_node->set(p_property, p_value, &valid);
+ rpc_sender_id = temp_id;
if (!valid) {
String error = "rset() aborted in local set, property not found: - " + String(p_property);
@@ -721,8 +735,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
set_local = _should_call_local(rpc_mode, is_master, skip_rset);
if (set_local) {
+ int temp_id = rpc_sender_id;
+ rpc_sender_id = get_network_unique_id();
bool valid = p_node->get_script_instance()->set(p_property, p_value);
+ rpc_sender_id = temp_id;
if (!valid) {
String error = "rset() aborted in local script set, property not found: - " + String(p_property);
@@ -733,8 +750,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
}
- if (skip_rset)
+ if (skip_rset) {
+ ERR_EXPLAIN("RSET for '" + p_property + "' on yourself is not allowed by selected mode");
+ ERR_FAIL_COND(!set_local);
return;
+ }
const Variant *vptr = &p_value;
@@ -818,6 +838,16 @@ Vector<int> MultiplayerAPI::get_network_connected_peers() const {
return ret;
}
+void MultiplayerAPI::set_allow_object_decoding(bool p_enable) {
+
+ allow_object_decoding = p_enable;
+}
+
+bool MultiplayerAPI::is_object_decoding_allowed() const {
+
+ return allow_object_decoding;
+}
+
void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
@@ -838,6 +868,10 @@ void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &MultiplayerAPI::get_network_connected_peers);
ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &MultiplayerAPI::set_refuse_new_network_connections);
ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &MultiplayerAPI::is_refusing_new_network_connections);
+ ClassDB::bind_method(D_METHOD("set_allow_object_decoding", "enable"), &MultiplayerAPI::set_allow_object_decoding);
+ ClassDB::bind_method(D_METHOD("is_object_decoding_allowed"), &MultiplayerAPI::is_object_decoding_allowed);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer");
@@ -859,7 +893,8 @@ void MultiplayerAPI::_bind_methods() {
BIND_ENUM_CONSTANT(RPC_MODE_PUPPETSYNC);
}
-MultiplayerAPI::MultiplayerAPI() {
+MultiplayerAPI::MultiplayerAPI() :
+ allow_object_decoding(false) {
rpc_sender_id = 0;
root_node = NULL;
clear();
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index a9cf77aaba..779dd043bd 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -63,6 +63,7 @@ private:
int last_send_cache_id;
Vector<uint8_t> packet_cache;
Node *root_node;
+ bool allow_object_decoding;
protected:
static void _bind_methods();
@@ -126,6 +127,9 @@ public:
void set_refuse_new_network_connections(bool p_refuse);
bool is_refusing_new_network_connections() const;
+ void set_allow_object_decoding(bool p_enable);
+ bool is_object_decoding_allowed() const;
+
MultiplayerAPI();
~MultiplayerAPI();
};
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index d7bfdbbb37..c77c81f9e2 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -79,7 +79,7 @@ Error PacketPeer::put_packet_buffer(const PoolVector<uint8_t> &p_buffer) {
return put_packet(&r[0], len);
}
-Error PacketPeer::get_var(Variant &r_variant) {
+Error PacketPeer::get_var(Variant &r_variant, bool p_allow_objects) {
const uint8_t *buffer;
int buffer_size;
@@ -87,13 +87,13 @@ Error PacketPeer::get_var(Variant &r_variant) {
if (err)
return err;
- return decode_variant(r_variant, buffer, buffer_size, NULL, allow_object_decoding);
+ return decode_variant(r_variant, buffer, buffer_size, NULL, p_allow_objects || allow_object_decoding);
}
-Error PacketPeer::put_var(const Variant &p_packet) {
+Error PacketPeer::put_var(const Variant &p_packet, bool p_full_objects) {
int len;
- Error err = encode_variant(p_packet, NULL, len, !allow_object_decoding); // compute len first
+ Error err = encode_variant(p_packet, NULL, len, p_full_objects || allow_object_decoding); // compute len first
if (err)
return err;
@@ -102,15 +102,15 @@ Error PacketPeer::put_var(const Variant &p_packet) {
uint8_t *buf = (uint8_t *)alloca(len);
ERR_FAIL_COND_V(!buf, ERR_OUT_OF_MEMORY);
- err = encode_variant(p_packet, buf, len, !allow_object_decoding);
+ err = encode_variant(p_packet, buf, len, p_full_objects || allow_object_decoding);
ERR_FAIL_COND_V(err, err);
return put_packet(buf, len);
}
-Variant PacketPeer::_bnd_get_var() {
+Variant PacketPeer::_bnd_get_var(bool p_allow_objects) {
Variant var;
- get_var(var);
+ get_var(var, p_allow_objects);
return var;
};
@@ -132,8 +132,8 @@ Error PacketPeer::_get_packet_error() const {
void PacketPeer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_var"), &PacketPeer::_bnd_get_var);
- ClassDB::bind_method(D_METHOD("put_var", "var"), &PacketPeer::put_var);
+ ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &PacketPeer::_bnd_get_var, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("put_var", "var", "full_objects"), &PacketPeer::put_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_packet"), &PacketPeer::_get_packet);
ClassDB::bind_method(D_METHOD("put_packet", "buffer"), &PacketPeer::_put_packet);
ClassDB::bind_method(D_METHOD("get_packet_error"), &PacketPeer::_get_packet_error);
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index 48c50eb76b..6475e4fed9 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -39,8 +39,7 @@ class PacketPeer : public Reference {
GDCLASS(PacketPeer, Reference);
- Variant _bnd_get_var();
- void _bnd_put_var(const Variant &p_var);
+ Variant _bnd_get_var(bool p_allow_objects = false);
static void _bind_methods();
@@ -64,8 +63,8 @@ public:
virtual Error get_packet_buffer(PoolVector<uint8_t> &r_buffer);
virtual Error put_packet_buffer(const PoolVector<uint8_t> &p_buffer);
- virtual Error get_var(Variant &r_variant);
- virtual Error put_var(const Variant &p_packet);
+ virtual Error get_var(Variant &r_variant, bool p_allow_objects = false);
+ virtual Error put_var(const Variant &p_packet, bool p_full_objects = false);
void set_allow_object_decoding(bool p_enable);
bool is_object_decoding_allowed() const;
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 42070cd132..f25abc4aab 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1725,7 +1725,8 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
get_string_index(np.get_subname(i));
} break;
- default: {}
+ default: {
+ }
}
}
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index b5fa412576..4a58d37ca5 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -94,6 +94,8 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
r_path_and_type.type = value;
} else if (assign == "importer") {
r_path_and_type.importer = value;
+ } else if (assign == "group_file") {
+ r_path_and_type.group_file = value;
} else if (assign == "metadata") {
r_path_and_type.metadata = value;
} else if (assign == "valid") {
@@ -294,6 +296,14 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat
memdelete(f);
}
+String ResourceFormatImporter::get_import_group_file(const String &p_path) const {
+
+ bool valid = true;
+ PathAndType pat;
+ _get_path_and_type(p_path, pat, &valid);
+ return valid ? pat.group_file : String();
+}
+
bool ResourceFormatImporter::is_import_valid(const String &p_path) const {
bool valid = true;
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index 1c146c33d7..2e01989564 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -43,6 +43,7 @@ class ResourceFormatImporter : public ResourceFormatLoader {
String path;
String type;
String importer;
+ String group_file;
Variant metadata;
};
@@ -69,6 +70,7 @@ public:
virtual bool is_import_valid(const String &p_path) const;
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
virtual bool is_imported(const String &p_path) const { return recognize_path(p_path); }
+ virtual String get_import_group_file(const String &p_path) const;
virtual bool exists(const String &p_path) const;
virtual bool can_be_imported(const String &p_path) const;
@@ -120,8 +122,11 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const = 0;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const = 0;
+ virtual String get_option_group_file() const { return String(); }
virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL) = 0;
+
+ virtual Error import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant> > &p_source_file_options, const Map<String, String> &p_base_paths) { return ERR_UNAVAILABLE; }
virtual bool are_import_settings_valid(const String &p_path) const { return true; }
virtual String get_import_settings_string() const { return String(); }
};
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index e4b694b64f..56d3b8b133 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -608,6 +608,30 @@ int ResourceLoader::get_import_order(const String &p_path) {
return 0;
}
+String ResourceLoader::get_import_group_file(const String &p_path) {
+ String path = _path_remap(p_path);
+
+ String local_path;
+ if (path.is_rel_path())
+ local_path = "res://" + path;
+ else
+ local_path = ProjectSettings::get_singleton()->localize_path(path);
+
+ for (int i = 0; i < loader_count; i++) {
+
+ if (!loader[i]->recognize_path(local_path))
+ continue;
+ /*
+ if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
+ continue;
+ */
+
+ return loader[i]->get_import_group_file(p_path);
+ }
+
+ return String(); //not found
+}
+
bool ResourceLoader::is_import_valid(const String &p_path) {
String path = _path_remap(p_path);
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index ca7610a0d2..9e7020be7c 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -81,6 +81,7 @@ public:
virtual bool is_import_valid(const String &p_path) const { return true; }
virtual bool is_imported(const String &p_path) const { return false; }
virtual int get_import_order(const String &p_path) const { return 0; }
+ virtual String get_import_group_file(const String &p_path) const { return ""; } //no group
virtual ~ResourceFormatLoader() {}
};
@@ -155,6 +156,7 @@ public:
static void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
static Error rename_dependencies(const String &p_path, const Map<String, String> &p_map);
static bool is_import_valid(const String &p_path);
+ static String get_import_group_file(const String &p_path);
static bool is_imported(const String &p_path);
static int get_import_order(const String &p_path);
diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp
index 3042c0f60a..6ad24a5f3a 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -221,14 +221,14 @@ void StreamPeer::put_utf8_string(const String &p_string) {
put_u32(cs.length());
put_data((const uint8_t *)cs.get_data(), cs.length());
}
-void StreamPeer::put_var(const Variant &p_variant) {
+void StreamPeer::put_var(const Variant &p_variant, bool p_full_objects) {
int len = 0;
Vector<uint8_t> buf;
- encode_variant(p_variant, NULL, len);
+ encode_variant(p_variant, NULL, len, p_full_objects);
buf.resize(len);
put_32(len);
- encode_variant(p_variant, buf.ptrw(), len);
+ encode_variant(p_variant, buf.ptrw(), len, p_full_objects);
put_data(buf.ptr(), buf.size());
}
@@ -359,7 +359,7 @@ String StreamPeer::get_utf8_string(int p_bytes) {
ret.parse_utf8((const char *)buf.ptr(), buf.size());
return ret;
}
-Variant StreamPeer::get_var() {
+Variant StreamPeer::get_var(bool p_allow_objects) {
int len = get_32();
Vector<uint8_t> var;
@@ -369,7 +369,7 @@ Variant StreamPeer::get_var() {
ERR_FAIL_COND_V(err != OK, Variant());
Variant ret;
- decode_variant(ret, var.ptr(), len);
+ decode_variant(ret, var.ptr(), len, NULL, p_allow_objects);
return ret;
}
@@ -398,7 +398,7 @@ void StreamPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("put_double", "value"), &StreamPeer::put_double);
ClassDB::bind_method(D_METHOD("put_string", "value"), &StreamPeer::put_string);
ClassDB::bind_method(D_METHOD("put_utf8_string", "value"), &StreamPeer::put_utf8_string);
- ClassDB::bind_method(D_METHOD("put_var", "value"), &StreamPeer::put_var);
+ ClassDB::bind_method(D_METHOD("put_var", "value", "full_objects"), &StreamPeer::put_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_8"), &StreamPeer::get_8);
ClassDB::bind_method(D_METHOD("get_u8"), &StreamPeer::get_u8);
@@ -412,7 +412,7 @@ void StreamPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_double"), &StreamPeer::get_double);
ClassDB::bind_method(D_METHOD("get_string", "bytes"), &StreamPeer::get_string, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_utf8_string", "bytes"), &StreamPeer::get_utf8_string, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_var"), &StreamPeer::get_var);
+ ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &StreamPeer::get_var, DEFVAL(false));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian_enabled");
}
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index 059ccd016c..65e70995ad 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -73,7 +73,7 @@ public:
void put_double(double p_val);
void put_string(const String &p_string);
void put_utf8_string(const String &p_string);
- void put_var(const Variant &p_variant);
+ void put_var(const Variant &p_variant, bool p_full_objects = false);
uint8_t get_u8();
int8_t get_8();
@@ -87,7 +87,7 @@ public:
double get_double();
String get_string(int p_bytes = -1);
String get_utf8_string(int p_bytes = -1);
- Variant get_var();
+ Variant get_var(bool p_allow_objects = false);
StreamPeer() { big_endian = false; }
};
diff --git a/core/io/zip_io.h b/core/io/zip_io.h
index fb63878a4c..4eb1c8b46c 100644
--- a/core/io/zip_io.h
+++ b/core/io/zip_io.h
@@ -33,7 +33,7 @@
#include "core/os/file_access.h"
-// Not direclty used in this header, but assumed available in downstream users
+// Not directly used in this header, but assumed available in downstream users
// like platform/*/export/export.cpp. Could be fixed, but probably better to have
// thirdparty includes in as little headers as possible.
#include "thirdparty/minizip/unzip.h"
diff --git a/core/list.h b/core/list.h
index c26aad6463..103a82a31d 100644
--- a/core/list.h
+++ b/core/list.h
@@ -503,8 +503,7 @@ public:
if (p_I->prev_ptr)
p_I->prev_ptr->next_ptr = p_I->next_ptr;
- if (p_I->next_ptr)
- p_I->next_ptr->prev_ptr = p_I->prev_ptr;
+ p_I->next_ptr->prev_ptr = p_I->prev_ptr;
_data->last->next_ptr = p_I;
p_I->prev_ptr = _data->last;
@@ -538,8 +537,7 @@ public:
if (_data->last == p_I)
_data->last = p_I->prev_ptr;
- if (p_I->prev_ptr)
- p_I->prev_ptr->next_ptr = p_I->next_ptr;
+ p_I->prev_ptr->next_ptr = p_I->next_ptr;
if (p_I->next_ptr)
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
@@ -691,6 +689,10 @@ public:
memdelete_arr(aux_buffer);
}
+ const void *id() const {
+ return (void *)_data;
+ }
+
/**
* copy constructor for the list
*/
diff --git a/core/make_binders.py b/core/make_binders.py
index 4c61b90d99..5c1c66cab6 100644
--- a/core/make_binders.py
+++ b/core/make_binders.py
@@ -9,6 +9,12 @@ public:
$ifret R$ $ifnoret void$ (T::*method)($arg, P@$) $ifconst const$;
#ifdef DEBUG_METHODS_ENABLED
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
+ $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
+ $
+ return GodotTypeInfo::METADATA_NONE;
+ }
Variant::Type _get_argument_type(int p_argument) const {
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
$arg if (p_argument==(@-1)) return (Variant::Type)GetTypeInfo<P@>::VARIANT_TYPE;
@@ -94,6 +100,12 @@ public:
#ifdef DEBUG_METHODS_ENABLED
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
+ $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
+ $
+ return GodotTypeInfo::METADATA_NONE;
+ }
Variant::Type _get_argument_type(int p_argument) const {
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 6c3b84d49a..3d71e66f80 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -54,7 +54,9 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
pt->pos = p_pos;
pt->weight_scale = p_weight_scale;
pt->prev_point = NULL;
- pt->last_pass = 0;
+ pt->open_pass = 0;
+ pt->closed_pass = 0;
+ pt->enabled = true;
points[p_id] = pt;
} else {
points[p_id]->pos = p_pos;
@@ -242,79 +244,65 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
pass++;
- SelfList<Point>::List open_list;
+ if (!end_point->enabled)
+ return false;
bool found_route = false;
- for (Set<Point *>::Element *E = begin_point->neighbours.front(); E; E = E->next()) {
+ Vector<Point *> open_list;
+ SortArray<Point *, SortPoints> sorter;
- Point *n = E->get();
- n->prev_point = begin_point;
- n->distance = _compute_cost(begin_point->id, n->id) * n->weight_scale;
- n->last_pass = pass;
- open_list.add(&n->list);
- }
+ begin_point->g_score = 0;
+ begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
+
+ open_list.push_back(begin_point);
while (true) {
- if (open_list.first() == NULL) {
- // No path found
+ if (open_list.size() == 0) // No path found
break;
- }
- // Check open list
-
- SelfList<Point> *least_cost_point = open_list.first();
- real_t least_cost = Math_INF;
-
- // TODO: Cache previous results
- for (SelfList<Point> *E = open_list.first(); E; E = E->next()) {
-
- Point *p = E->self();
- real_t cost = p->distance;
- cost += _estimate_cost(p->id, end_point->id);
+ Point *p = open_list[0]; // The currently processed point
- if (cost < least_cost) {
- least_cost_point = E;
- least_cost = cost;
- }
- }
-
- Point *p = least_cost_point->self();
if (p == end_point) {
found_route = true;
break;
}
+ sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list
+ open_list.remove(open_list.size() - 1);
+ p->closed_pass = pass; // Mark the point as closed
+
for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) {
- Point *e = E->get();
+ Point *e = E->get(); // The neighbour point
+
+ if (!e->enabled || e->closed_pass == pass)
+ continue;
+
+ real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * e->weight_scale;
- real_t distance = _compute_cost(p->id, e->id) * e->weight_scale + p->distance;
+ bool new_point = false;
- if (e->last_pass == pass) {
- // Already visited, is this cheaper?
+ if (e->open_pass != pass) { // The point wasn't inside the open list
- if (e->distance > distance) {
- e->prev_point = p;
- e->distance = distance;
- }
- } else {
- // Add to open neighbours
+ e->open_pass = pass;
+ open_list.push_back(e);
+ new_point = true;
+ } else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous
- e->prev_point = p;
- e->distance = distance;
- e->last_pass = pass; // Mark as used
- open_list.add(&e->list);
+ continue;
}
- }
- open_list.remove(least_cost_point);
- }
+ e->prev_point = p;
+ e->g_score = tentative_g_score;
+ e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
- // Clear the openf list
- while (open_list.first()) {
- open_list.remove(open_list.first());
+ if (new_point) // The position of the new points is already known
+ sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw());
+ else
+ sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw());
+ }
}
return found_route;
@@ -341,8 +329,6 @@ PoolVector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) {
ERR_FAIL_COND_V(!points.has(p_from_id), PoolVector<Vector3>());
ERR_FAIL_COND_V(!points.has(p_to_id), PoolVector<Vector3>());
- pass++;
-
Point *a = points[p_from_id];
Point *b = points[p_to_id];
@@ -392,8 +378,6 @@ PoolVector<int> AStar::get_id_path(int p_from_id, int p_to_id) {
ERR_FAIL_COND_V(!points.has(p_from_id), PoolVector<int>());
ERR_FAIL_COND_V(!points.has(p_to_id), PoolVector<int>());
- pass++;
-
Point *a = points[p_from_id];
Point *b = points[p_to_id];
@@ -438,6 +422,14 @@ PoolVector<int> AStar::get_id_path(int p_from_id, int p_to_id) {
return path;
}
+void AStar::set_point_disabled(int p_id, bool p_disabled) {
+ points[p_id]->enabled = !p_disabled;
+}
+
+bool AStar::is_point_disabled(int p_id) const {
+ return !points[p_id]->enabled;
+}
+
void AStar::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_available_point_id"), &AStar::get_available_point_id);
@@ -450,6 +442,9 @@ void AStar::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar::has_point);
ClassDB::bind_method(D_METHOD("get_points"), &AStar::get_points);
+ ClassDB::bind_method(D_METHOD("set_point_disabled", "id", "disabled"), &AStar::set_point_disabled, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar::is_point_disabled);
+
ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar::get_point_connections);
ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar::connect_points, DEFVAL(true));
diff --git a/core/math/a_star.h b/core/math/a_star.h
index d094bc4863..fac8a9d312 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -48,25 +48,34 @@ class AStar : public Reference {
struct Point {
- SelfList<Point> list;
-
int id;
Vector3 pos;
real_t weight_scale;
- uint64_t last_pass;
+ bool enabled;
Set<Point *> neighbours;
// Used for pathfinding
Point *prev_point;
- real_t distance;
-
- Point() :
- list(this) {}
+ real_t g_score;
+ real_t f_score;
+ uint64_t open_pass;
+ uint64_t closed_pass;
};
Map<int, Point *> points;
+ struct SortPoints {
+ _FORCE_INLINE_ bool operator()(const Point *A, const Point *B) const { // Returns true when the Point A is worse than Point B
+ if (A->f_score > B->f_score)
+ return true;
+ else if (A->f_score < B->f_score)
+ return false;
+ else
+ return A->g_score < B->g_score; // If the f_costs are the same then prioritize the points that are further away from the start
+ }
+ };
+
struct Segment {
union {
struct {
@@ -114,6 +123,9 @@ public:
PoolVector<int> get_point_connections(int p_id);
Array get_points();
+ void set_point_disabled(int p_id, bool p_disabled = true);
+ bool is_point_disabled(int p_id) const;
+
void connect_points(int p_id, int p_with_id, bool bidirectional = true);
void disconnect_points(int p_id, int p_with_id);
bool are_points_connected(int p_id, int p_with_id) const;
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index f970c510e0..98e4e33021 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -31,6 +31,7 @@
#ifndef AUDIOFRAME_H
#define AUDIOFRAME_H
+#include "core/math/vector2.h"
#include "core/typedefs.h"
static inline float undenormalise(volatile float f) {
@@ -122,6 +123,20 @@ struct AudioFrame {
r = p_frame.r;
}
+ _ALWAYS_INLINE_ AudioFrame operator=(const AudioFrame &p_frame) {
+ l = p_frame.l;
+ r = p_frame.r;
+ return *this;
+ }
+
+ _ALWAYS_INLINE_ operator Vector2() const {
+ return Vector2(l, r);
+ }
+
+ _ALWAYS_INLINE_ AudioFrame(const Vector2 &p_v2) {
+ l = p_v2.x;
+ r = p_v2.y;
+ }
_ALWAYS_INLINE_ AudioFrame() {}
};
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 8816e3639a..1540bc8fe1 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -557,11 +557,23 @@ void Basis::set_euler_yxz(const Vector3 &p_euler) {
*this = ymat * xmat * zmat;
}
-bool Basis::is_equal_approx(const Basis &a, const Basis &b) const {
+bool Basis::is_equal_approx(const Basis &a, const Basis &b, real_t p_epsilon) const {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- if (!Math::is_equal_approx_ratio(a.elements[i][j], b.elements[i][j], UNIT_EPSILON))
+ if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j], p_epsilon))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool Basis::is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon) const {
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (!Math::is_equal_approx_ratio(a.elements[i][j], b.elements[i][j], p_epsilon))
return false;
}
}
@@ -605,12 +617,14 @@ Basis::operator String() const {
Quat Basis::get_quat() const {
+#ifdef MATH_CHECKS
+ if (!is_rotation()) {
+ ERR_EXPLAIN("Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead.");
+ ERR_FAIL_V(Quat());
+ }
+#endif
/* Allow getting a quaternion from an unnormalized transform */
Basis m = *this;
- m.elements[0].normalize();
- m.elements[1].normalize();
- m.elements[2].normalize();
-
real_t trace = m.elements[0][0] + m.elements[1][1] + m.elements[2][2];
real_t temp[4];
@@ -799,21 +813,28 @@ void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) {
ERR_FAIL_COND(!p_axis.is_normalized());
#endif
Vector3 axis_sq(p_axis.x * p_axis.x, p_axis.y * p_axis.y, p_axis.z * p_axis.z);
-
real_t cosine = Math::cos(p_phi);
- real_t sine = Math::sin(p_phi);
-
elements[0][0] = axis_sq.x + cosine * (1.0 - axis_sq.x);
- elements[0][1] = p_axis.x * p_axis.y * (1.0 - cosine) - p_axis.z * sine;
- elements[0][2] = p_axis.z * p_axis.x * (1.0 - cosine) + p_axis.y * sine;
-
- elements[1][0] = p_axis.x * p_axis.y * (1.0 - cosine) + p_axis.z * sine;
elements[1][1] = axis_sq.y + cosine * (1.0 - axis_sq.y);
- elements[1][2] = p_axis.y * p_axis.z * (1.0 - cosine) - p_axis.x * sine;
-
- elements[2][0] = p_axis.z * p_axis.x * (1.0 - cosine) - p_axis.y * sine;
- elements[2][1] = p_axis.y * p_axis.z * (1.0 - cosine) + p_axis.x * sine;
elements[2][2] = axis_sq.z + cosine * (1.0 - axis_sq.z);
+
+ real_t sine = Math::sin(p_phi);
+ real_t t = 1 - cosine;
+
+ real_t xyzt = p_axis.x * p_axis.y * t;
+ real_t zyxs = p_axis.z * sine;
+ elements[0][1] = xyzt - zyxs;
+ elements[1][0] = xyzt + zyxs;
+
+ xyzt = p_axis.x * p_axis.z * t;
+ zyxs = p_axis.y * sine;
+ elements[0][2] = xyzt + zyxs;
+ elements[2][0] = xyzt - zyxs;
+
+ xyzt = p_axis.y * p_axis.z * t;
+ zyxs = p_axis.x * sine;
+ elements[1][2] = xyzt - zyxs;
+ elements[2][1] = xyzt + zyxs;
}
void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) {
diff --git a/core/math/basis.h b/core/math/basis.h
index 128e56b494..75037c2c52 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -133,7 +133,8 @@ public:
return elements[0][2] * v[0] + elements[1][2] * v[1] + elements[2][2] * v[2];
}
- bool is_equal_approx(const Basis &a, const Basis &b) const;
+ bool is_equal_approx(const Basis &a, const Basis &b, real_t p_epsilon = CMP_EPSILON) const;
+ bool is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon = UNIT_EPSILON) const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index caf08c7379..f615cc8c65 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -210,6 +210,14 @@ void CameraMatrix::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, r
te[15] = 0;
}
+void CameraMatrix::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) {
+ if (!p_flip_fov) {
+ p_size *= p_aspect;
+ }
+
+ set_frustum(-p_size / 2 + p_offset.x, +p_size / 2 + p_offset.x, -p_size / p_aspect / 2 + p_offset.y, +p_size / p_aspect / 2 + p_offset.y, p_near, p_far);
+}
+
real_t CameraMatrix::get_z_far() const {
const real_t *matrix = (const real_t *)this->matrix;
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 015588a8cb..3bcf48f5da 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -61,6 +61,7 @@ struct CameraMatrix {
void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar);
void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
+ void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
diff --git a/core/math/delaunay.h b/core/math/delaunay.h
index bd0cf97937..ed52c506db 100644
--- a/core/math/delaunay.h
+++ b/core/math/delaunay.h
@@ -80,11 +80,11 @@ public:
}
static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) {
- if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON) {
+ if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]))) {
return true;
}
- if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON) {
+ if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]))) {
return true;
}
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 99251d80e3..079c9b524f 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -64,10 +64,12 @@ const char *Expression::func_name[Expression::FUNC_MAX] = {
"is_inf",
"ease",
"decimals",
+ "step_decimals",
"stepify",
"lerp",
"inverse_lerp",
"range_lerp",
+ "smoothstep",
"dectime",
"randomize",
"randi",
@@ -148,6 +150,7 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
case MATH_ISNAN:
case MATH_ISINF:
case MATH_DECIMALS:
+ case MATH_STEP_DECIMALS:
case MATH_SEED:
case MATH_RANDSEED:
case MATH_DEG2RAD:
@@ -164,10 +167,10 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
case TEXT_PRINTRAW:
case VAR_TO_STR:
case STR_TO_VAR:
- case VAR_TO_BYTES:
- case BYTES_TO_VAR:
case TYPE_EXISTS:
return 1;
+ case VAR_TO_BYTES:
+ case BYTES_TO_VAR:
case MATH_ATAN2:
case MATH_FMOD:
case MATH_FPOSMOD:
@@ -185,6 +188,7 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
return 2;
case MATH_LERP:
case MATH_INVERSE_LERP:
+ case MATH_SMOOTHSTEP:
case MATH_DECTIME:
case MATH_WRAP:
case MATH_WRAPF:
@@ -363,6 +367,11 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
VALIDATE_ARG_NUM(0);
*r_return = Math::step_decimals((double)*p_inputs[0]);
} break;
+ case MATH_STEP_DECIMALS: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::step_decimals((double)*p_inputs[0]);
+ } break;
case MATH_STEPIFY: {
VALIDATE_ARG_NUM(0);
@@ -392,6 +401,12 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
VALIDATE_ARG_NUM(4);
*r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
} break;
+ case MATH_SMOOTHSTEP: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
case MATH_DECTIME: {
VALIDATE_ARG_NUM(0);
@@ -696,8 +711,9 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
case VAR_TO_BYTES: {
PoolByteArray barr;
+ bool full_objects = *p_inputs[1];
int len;
- Error err = encode_variant(*p_inputs[0], NULL, len);
+ Error err = encode_variant(*p_inputs[0], NULL, len, full_objects);
if (err) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
@@ -709,7 +725,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
barr.resize(len);
{
PoolByteArray::Write w = barr.write();
- encode_variant(*p_inputs[0], w.ptr(), len);
+ encode_variant(*p_inputs[0], w.ptr(), len, full_objects);
}
*r_return = barr;
} break;
@@ -724,10 +740,11 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
}
PoolByteArray varr = *p_inputs[0];
+ bool allow_objects = *p_inputs[1];
Variant ret;
{
PoolByteArray::Read r = varr.read();
- Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
+ Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects);
if (err != OK) {
r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
@@ -750,7 +767,8 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
*r_return = String(color);
} break;
- default: {}
+ default: {
+ }
}
}
@@ -1669,7 +1687,8 @@ Expression::ENode *Expression::_parse_expression() {
case TK_OP_BIT_OR: op = Variant::OP_BIT_OR; break;
case TK_OP_BIT_XOR: op = Variant::OP_BIT_XOR; break;
case TK_OP_BIT_INVERT: op = Variant::OP_BIT_NEGATE; break;
- default: {};
+ default: {
+ };
}
if (op == Variant::OP_MAX) { //stop appending stuff
diff --git a/core/math/expression.h b/core/math/expression.h
index fa0878c93c..f20619f0b6 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -62,10 +62,12 @@ public:
MATH_ISINF,
MATH_EASE,
MATH_DECIMALS,
+ MATH_STEP_DECIMALS,
MATH_STEPIFY,
MATH_LERP,
MATH_INVERSE_LERP,
MATH_RANGE_LERP,
+ MATH_SMOOTHSTEP,
MATH_DECTIME,
MATH_RANDOMIZE,
MATH_RAND,
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index a84b5a16c7..8314cb827c 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -31,8 +31,11 @@
#include "geometry.h"
#include "core/print_string.h"
+#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/triangulator.h"
+#define SCALE_FACTOR 100000.0 // based on CMP_EPSILON
+
/* this implementation is very inefficient, commenting unless bugs happen. See the other one.
bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) {
@@ -836,7 +839,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
Vector3 rel = edge1_A - edge0_A;
real_t den = clip.normal.dot(rel);
- if (Math::abs(den) < CMP_EPSILON)
+ if (Math::is_zero_approx(den))
continue; // point too short
real_t dist = -(clip.normal.dot(edge0_A) - clip.d) / den;
@@ -1134,3 +1137,106 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu
r_size = Size2(results[best].max_w, results[best].max_h);
}
+
+Vector<Vector<Point2> > Geometry::_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;
+
+ ClipType op = ctUnion;
+
+ switch (p_op) {
+ case OPERATION_UNION: op = ctUnion; break;
+ case OPERATION_DIFFERENCE: op = ctDifference; break;
+ case OPERATION_INTERSECTION: op = ctIntersection; break;
+ case OPERATION_XOR: op = ctXor; break;
+ }
+ Path path_a, path_b;
+
+ // Need to scale points (Clipper's requirement for robust computation)
+ for (int i = 0; i != p_polypath_a.size(); ++i) {
+ path_a << IntPoint(p_polypath_a[i].x * SCALE_FACTOR, p_polypath_a[i].y * SCALE_FACTOR);
+ }
+ for (int i = 0; i != p_polypath_b.size(); ++i) {
+ path_b << IntPoint(p_polypath_b[i].x * SCALE_FACTOR, p_polypath_b[i].y * SCALE_FACTOR);
+ }
+ 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;
+
+ if (is_a_open) {
+ PolyTree tree; // needed to populate polylines
+ clp.Execute(op, tree);
+ OpenPathsFromPolyTree(tree, paths);
+ } else {
+ clp.Execute(op, paths); // works on closed polygons only
+ }
+ // Have to scale points down now
+ Vector<Vector<Point2> > polypaths;
+
+ 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) / SCALE_FACTOR,
+ static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR));
+ }
+ polypaths.push_back(polypath);
+ }
+ return polypaths;
+}
+
+Vector<Vector<Point2> > Geometry::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
+
+ using namespace ClipperLib;
+
+ JoinType jt = jtSquare;
+
+ switch (p_join_type) {
+ case JOIN_SQUARE: jt = jtSquare; break;
+ case JOIN_ROUND: jt = jtRound; break;
+ case JOIN_MITER: jt = jtMiter; break;
+ }
+
+ EndType et = etClosedPolygon;
+
+ switch (p_end_type) {
+ case END_POLYGON: et = etClosedPolygon; break;
+ case END_JOINED: et = etClosedLine; break;
+ case END_BUTT: et = etOpenButt; break;
+ case END_SQUARE: et = etOpenSquare; break;
+ case END_ROUND: et = etOpenRound; break;
+ }
+ ClipperOffset co;
+ Path path;
+
+ // Need to scale points (Clipper's requirement for robust computation)
+ for (int i = 0; i != p_polypath.size(); ++i) {
+ path << IntPoint(p_polypath[i].x * SCALE_FACTOR, p_polypath[i].y * SCALE_FACTOR);
+ }
+ co.AddPath(path, jt, et);
+
+ Paths paths;
+ co.Execute(paths, p_delta * SCALE_FACTOR); // inflate/deflate
+
+ // Have to scale points down now
+ Vector<Vector<Point2> > polypaths;
+
+ 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) / SCALE_FACTOR,
+ static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR));
+ }
+ polypaths.push_back(polypath);
+ }
+ return polypaths;
+}
diff --git a/core/math/geometry.h b/core/math/geometry.h
index 4b478b6b16..0e144e491f 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -31,6 +31,7 @@
#ifndef GEOMETRY_H
#define GEOMETRY_H
+#include "core/math/delaunay.h"
#include "core/math/face3.h"
#include "core/math/rect2.h"
#include "core/math/triangulate.h"
@@ -181,8 +182,8 @@ public:
}
}
// finally do the division to get sc and tc
- sc = (Math::abs(sN) < CMP_EPSILON ? 0.0 : sN / sD);
- tc = (Math::abs(tN) < CMP_EPSILON ? 0.0 : tN / tD);
+ sc = (Math::is_zero_approx(sN) ? 0.0 : sN / sD);
+ tc = (Math::is_zero_approx(tN) ? 0.0 : tN / tD);
// get the difference of the two closest points
Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
@@ -195,7 +196,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = p_dir.cross(e2);
real_t a = e1.dot(h);
- if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test
+ if (Math::is_zero_approx(a)) // parallel test
return false;
real_t f = 1.0 / a;
@@ -233,7 +234,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = rel.cross(e2);
real_t a = e1.dot(h);
- if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test
+ if (Math::is_zero_approx(a)) // parallel test
return false;
real_t f = 1.0 / a;
@@ -535,7 +536,7 @@ public:
// see http://paulbourke.net/geometry/pointlineplane/
const real_t denom = p_dir_b.y * p_dir_a.x - p_dir_b.x * p_dir_a.y;
- if (Math::abs(denom) < CMP_EPSILON) { // parallel?
+ if (Math::is_zero_approx(denom)) { // parallel?
return false;
}
@@ -702,9 +703,11 @@ public:
/* if we can assume that the line segment starts outside the circle (e.g. for continuous time collision detection) then the following can be skipped and we can just return the equivalent of res1 */
sqrtterm = Math::sqrt(sqrtterm);
real_t res1 = (-b - sqrtterm) / (2 * a);
- //real_t res2 = ( -b + sqrtterm ) / (2 * a);
+ real_t res2 = (-b + sqrtterm) / (2 * a);
- return (res1 >= 0 && res1 <= 1) ? res1 : -1;
+ if (res1 >= 0 && res1 <= 1) return res1;
+ if (res2 >= 0 && res2 <= 1) return res2;
+ return -1;
}
static inline Vector<Vector3> clip_polygon(const Vector<Vector3> &polygon, const Plane &p_plane) {
@@ -783,6 +786,91 @@ public:
return clipped;
}
+ enum PolyBooleanOperation {
+ OPERATION_UNION,
+ OPERATION_DIFFERENCE,
+ OPERATION_INTERSECTION,
+ OPERATION_XOR
+ };
+ enum PolyJoinType {
+ JOIN_SQUARE,
+ JOIN_ROUND,
+ JOIN_MITER
+ };
+ enum PolyEndType {
+ END_POLYGON,
+ END_JOINED,
+ END_BUTT,
+ END_SQUARE,
+ END_ROUND
+ };
+
+ static Vector<Vector<Point2> > merge_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
+
+ return _polypaths_do_operation(OPERATION_UNION, p_polygon_a, p_polygon_b);
+ }
+
+ static Vector<Vector<Point2> > clip_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
+
+ return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polygon_a, p_polygon_b);
+ }
+
+ static Vector<Vector<Point2> > intersect_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
+
+ return _polypaths_do_operation(OPERATION_INTERSECTION, p_polygon_a, p_polygon_b);
+ }
+
+ static Vector<Vector<Point2> > exclude_polygons_2d(const Vector<Point2> &p_polygon_a, const Vector<Point2> &p_polygon_b) {
+
+ return _polypaths_do_operation(OPERATION_XOR, p_polygon_a, p_polygon_b);
+ }
+
+ static Vector<Vector<Point2> > clip_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+
+ return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polyline, p_polygon, true);
+ }
+
+ static Vector<Vector<Point2> > intersect_polyline_with_polygon_2d(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+
+ return _polypaths_do_operation(OPERATION_INTERSECTION, p_polyline, p_polygon, true);
+ }
+
+ static Vector<Vector<Point2> > offset_polygon_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
+
+ return _polypath_offset(p_polygon, p_delta, p_join_type, END_POLYGON);
+ }
+
+ static Vector<Vector<Point2> > offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
+
+ ERR_EXPLAIN("Attempt to offset a polyline like a polygon (use offset_polygon_2d instead).");
+ ERR_FAIL_COND_V(p_end_type == END_POLYGON, Vector<Vector<Point2> >());
+
+ return _polypath_offset(p_polygon, p_delta, p_join_type, p_end_type);
+ }
+
+ static Vector<Point2> transform_points_2d(const Vector<Point2> &p_points, const Transform2D &p_mat) {
+
+ Vector<Point2> points;
+
+ for (int i = 0; i < p_points.size(); ++i) {
+ points.push_back(p_mat.xform(p_points[i]));
+ }
+ return points;
+ }
+
+ static Vector<int> triangulate_delaunay_2d(const Vector<Vector2> &p_points) {
+
+ Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(p_points);
+ Vector<int> triangles;
+
+ for (int i = 0; i < tr.size(); i++) {
+ triangles.push_back(tr[i].points[0]);
+ triangles.push_back(tr[i].points[1]);
+ triangles.push_back(tr[i].points[2]);
+ }
+ return triangles;
+ }
+
static Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon) {
Vector<int> triangles;
@@ -831,7 +919,7 @@ public:
further_away_opposite.y = MIN(p[i].y, further_away_opposite.y);
}
- further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312); // make point outside that wont intersect with points in segment from p_point
+ further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312); // make point outside that won't intersect with points in segment from p_point
int intersections = 0;
for (int i = 0; i < c; i++) {
@@ -949,7 +1037,6 @@ public:
H.resize(k);
return H;
}
-
static Vector<Vector<Vector2> > decompose_polygon_in_convex(Vector<Point2> polygon);
static MeshData build_convex_mesh(const PoolVector<Plane> &p_planes);
@@ -959,6 +1046,10 @@ public:
static PoolVector<Plane> build_capsule_planes(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size);
+
+private:
+ static Vector<Vector<Point2> > _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false);
+ static Vector<Vector<Point2> > _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type);
};
#endif
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 17112d8940..82b5b56c01 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -61,6 +61,12 @@ public:
static _ALWAYS_INLINE_ double sinh(double p_x) { return ::sinh(p_x); }
static _ALWAYS_INLINE_ float sinh(float p_x) { return ::sinhf(p_x); }
+ static _ALWAYS_INLINE_ float sinc(float p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
+ static _ALWAYS_INLINE_ double sinc(double p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
+
+ static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc(Math_PI * p_x); }
+ static _ALWAYS_INLINE_ double sincn(double p_x) { return sinc(Math_PI * p_x); }
+
static _ALWAYS_INLINE_ double cosh(double p_x) { return ::cosh(p_x); }
static _ALWAYS_INLINE_ float cosh(float p_x) { return ::coshf(p_x); }
@@ -208,6 +214,17 @@ public:
static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_weight) {
+ if (is_equal_approx(p_from, p_to)) return p_from;
+ double x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
+ return x * x * (3.0 - 2.0 * x);
+ }
+ static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_weight) {
+ if (is_equal_approx(p_from, p_to)) return p_from;
+ float x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
+ return x * x * (3.0f - 2.0f * x);
+ }
+
static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
@@ -249,11 +266,11 @@ public:
static float random(float from, float to);
static real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); }
- static _ALWAYS_INLINE_ bool is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON) {
+ static _ALWAYS_INLINE_ bool is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON, real_t min_epsilon = CMP_EPSILON) {
// this is an approximate way to check that numbers are close, as a ratio of their average size
// helps compare approximate numbers that may be very big or very small
real_t diff = abs(a - b);
- if (diff == 0.0) {
+ if (diff == 0.0 || diff < min_epsilon) {
return true;
}
real_t avg_size = (abs(a) + abs(b)) / 2.0;
@@ -261,13 +278,20 @@ public:
return diff < epsilon;
}
- static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t epsilon = CMP_EPSILON) {
- // TODO: Comparing floats for approximate-equality is non-trivial.
- // Using epsilon should cover the typical cases in Godot (where a == b is used to compare two reals), such as matrix and vector comparison operators.
- // A proper implementation in terms of ULPs should eventually replace the contents of this function.
- // See https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ for details.
+ static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
+ real_t tolerance = CMP_EPSILON * abs(a);
+ if (tolerance < CMP_EPSILON) {
+ tolerance = CMP_EPSILON;
+ }
+ return abs(a - b) < tolerance;
+ }
+
+ static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t tolerance) {
+ return abs(a - b) < tolerance;
+ }
- return abs(a - b) < epsilon;
+ static _ALWAYS_INLINE_ bool is_zero_approx(real_t s) {
+ return abs(s) < CMP_EPSILON;
}
static _ALWAYS_INLINE_ float absf(float g) {
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index cd3cbce300..b01853c4ac 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -110,7 +110,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
- if (Math::abs(den) <= CMP_EPSILON) {
+ if (Math::is_zero_approx(den)) {
return false;
}
@@ -135,7 +135,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
- if (Math::abs(den) <= CMP_EPSILON) {
+ if (Math::is_zero_approx(den)) {
return false;
}
diff --git a/core/math/plane.h b/core/math/plane.h
index 1c6e4b816b..ec817edd2c 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -125,12 +125,12 @@ Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_
bool Plane::operator==(const Plane &p_plane) const {
- return normal == p_plane.normal && d == p_plane.d;
+ return normal == p_plane.normal && Math::is_equal_approx(d, p_plane.d);
}
bool Plane::operator!=(const Plane &p_plane) const {
- return normal != p_plane.normal || d != p_plane.d;
+ return normal != p_plane.normal || !Math::is_equal_approx(d, p_plane.d);
}
#endif // PLANE_H
diff --git a/core/math/quat.h b/core/math/quat.h
index 7d71ec03e8..8ed2fa7cc2 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -131,6 +131,14 @@ public:
w(q.w) {
}
+ Quat operator=(const Quat &q) {
+ x = q.x;
+ y = q.y;
+ z = q.z;
+ w = q.w;
+ return *this;
+ }
+
Quat(const Vector3 &v0, const Vector3 &v1) // shortest arc
{
Vector3 c = v0.cross(v1);
diff --git a/core/math/random_number_generator.cpp b/core/math/random_number_generator.cpp
index fccc0f72fe..6add00c1d8 100644
--- a/core/math/random_number_generator.cpp
+++ b/core/math/random_number_generator.cpp
@@ -40,6 +40,7 @@ void RandomNumberGenerator::_bind_methods() {
ClassDB::bind_method(D_METHOD("randi"), &RandomNumberGenerator::randi);
ClassDB::bind_method(D_METHOD("randf"), &RandomNumberGenerator::randf);
+ ClassDB::bind_method(D_METHOD("randfn", "mean", "deviation"), &RandomNumberGenerator::randfn, DEFVAL(0.0), DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("randf_range", "from", "to"), &RandomNumberGenerator::randf_range);
ClassDB::bind_method(D_METHOD("randi_range", "from", "to"), &RandomNumberGenerator::randi_range);
ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize);
diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h
index 66c77b8ccf..6b6bcdd2cd 100644
--- a/core/math/random_number_generator.h
+++ b/core/math/random_number_generator.h
@@ -55,6 +55,8 @@ public:
_FORCE_INLINE_ real_t randf_range(real_t from, real_t to) { return randbase.random(from, to); }
+ _FORCE_INLINE_ real_t randfn(real_t mean = 0.0, real_t deviation = 1.0) { return randbase.randfn(mean, deviation); }
+
_FORCE_INLINE_ int randi_range(int from, int to) {
unsigned int ret = randbase.rand();
return ret % (to - from + 1) + from;
diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp
index 45467b32b2..8351bd138e 100644
--- a/core/math/random_pcg.cpp
+++ b/core/math/random_pcg.cpp
@@ -34,8 +34,7 @@
RandomPCG::RandomPCG(uint64_t p_seed, uint64_t p_inc) :
pcg(),
- current_seed(DEFAULT_SEED) {
- pcg.inc = p_inc;
+ current_inc(p_inc) {
seed(p_seed);
}
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index 230eb9a11b..0d1b311c0d 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -31,6 +31,8 @@
#ifndef RANDOM_PCG_H
#define RANDOM_PCG_H
+#include <math.h>
+
#include "core/math/math_defs.h"
#include "thirdparty/misc/pcg.h"
@@ -38,18 +40,18 @@
class RandomPCG {
pcg32_random_t pcg;
uint64_t current_seed; // seed with this to get the same state
+ uint64_t current_inc;
public:
static const uint64_t DEFAULT_SEED = 12047754176567800795U;
static const uint64_t DEFAULT_INC = PCG_DEFAULT_INC_64;
static const uint64_t RANDOM_MAX = 0xFFFFFFFF;
- RandomPCG(uint64_t p_seed = DEFAULT_SEED, uint64_t p_inc = PCG_DEFAULT_INC_64);
+ RandomPCG(uint64_t p_seed = DEFAULT_SEED, uint64_t p_inc = DEFAULT_INC);
_FORCE_INLINE_ void seed(uint64_t p_seed) {
current_seed = p_seed;
- pcg.state = p_seed;
- pcg32_random_r(&pcg); // Force changing internal state to avoid initial 0
+ pcg32_srandom_r(&pcg, current_seed, current_inc);
}
_FORCE_INLINE_ uint64_t get_seed() { return current_seed; }
@@ -61,6 +63,13 @@ public:
_FORCE_INLINE_ double randd() { return (double)rand() / (double)RANDOM_MAX; }
_FORCE_INLINE_ float randf() { return (float)rand() / (float)RANDOM_MAX; }
+ _FORCE_INLINE_ double randfn(double p_mean, double p_deviation) {
+ return p_mean + p_deviation * (cos(Math_TAU * randd()) * sqrt(-2.0 * log(randd()))); // Box-Muller transform
+ }
+ _FORCE_INLINE_ float randfn(float p_mean, float p_deviation) {
+ return p_mean + p_deviation * (cos(Math_TAU * randf()) * sqrt(-2.0 * log(randf()))); // Box-Muller transform
+ }
+
double random(double p_from, double p_to);
float random(float p_from, float p_to);
real_t random(int p_from, int p_to) { return (real_t)random((real_t)p_from, (real_t)p_to); }
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 901d372132..d636aa223f 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -67,7 +67,7 @@ struct Rect2 {
if (p_point.x < position.x) {
real_t d = position.x - p_point.x;
- dist = inside ? d : MIN(dist, d);
+ dist = d;
inside = false;
}
if (p_point.y < position.y) {
@@ -103,7 +103,7 @@ struct Rect2 {
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
}
- inline bool has_no_area() const {
+ _FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
@@ -154,8 +154,6 @@ struct Rect2 {
return true;
}
- inline bool no_area() const { return (size.width <= 0 || size.height <= 0); }
-
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -189,7 +187,7 @@ struct Rect2 {
return g;
}
- inline Rect2 expand(const Vector2 &p_vector) const {
+ _FORCE_INLINE_ Rect2 expand(const Vector2 &p_vector) const {
Rect2 r = *this;
r.expand_to(p_vector);
@@ -215,7 +213,7 @@ struct Rect2 {
size = end - begin;
}
- inline Rect2 abs() const {
+ _FORCE_INLINE_ Rect2 abs() const {
return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs());
}
@@ -265,7 +263,7 @@ struct Rect2i {
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
}
- inline bool has_no_area() const {
+ _FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
@@ -316,8 +314,6 @@ struct Rect2i {
return true;
}
- bool no_area() { return (size.width <= 0 || size.height <= 0); }
-
bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -331,6 +327,33 @@ struct Rect2i {
return g;
}
+ inline Rect2i grow_margin(Margin p_margin, int p_amount) const {
+ Rect2i g = *this;
+ g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0,
+ (MARGIN_TOP == p_margin) ? p_amount : 0,
+ (MARGIN_RIGHT == p_margin) ? p_amount : 0,
+ (MARGIN_BOTTOM == p_margin) ? p_amount : 0);
+ return g;
+ }
+
+ inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const {
+
+ Rect2i g = *this;
+ g.position.x -= p_left;
+ g.position.y -= p_top;
+ g.size.width += p_left + p_right;
+ g.size.height += p_top + p_bottom;
+
+ return g;
+ }
+
+ _FORCE_INLINE_ Rect2i expand(const Vector2i &p_vector) const {
+
+ Rect2i r = *this;
+ r.expand_to(p_vector);
+ return r;
+ }
+
inline void expand_to(const Point2i &p_vector) {
Point2i begin = position;
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 7d00158f3d..1d0387bd45 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -106,7 +106,7 @@ Size2 Transform2D::get_scale() const {
return Size2(elements[0].length(), det_sign * elements[1].length());
}
-void Transform2D::set_scale(Size2 &p_scale) {
+void Transform2D::set_scale(const Size2 &p_scale) {
elements[0].normalize();
elements[1].normalize();
elements[0] *= p_scale.x;
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index b9e7a36fb3..c44678674a 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -81,7 +81,7 @@ struct Transform2D {
real_t basis_determinant() const;
Size2 get_scale() const;
- void set_scale(Size2 &p_scale);
+ void set_scale(const Size2 &p_scale);
_FORCE_INLINE_ const Vector2 &get_origin() const { return elements[2]; }
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; }
diff --git a/core/math/vector2.h b/core/math/vector2.h
index a20326f667..a0c6024c9f 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -65,6 +65,7 @@ struct Vector2 {
real_t distance_squared_to(const Vector2 &p_vector2) const;
real_t angle_to(const Vector2 &p_vector2) const;
real_t angle_to_point(const Vector2 &p_vector2) const;
+ _FORCE_INLINE_ Vector2 direction_to(const Vector2 &p_b) const;
real_t dot(const Vector2 &p_other) const;
real_t cross(const Vector2 &p_other) const;
@@ -98,14 +99,15 @@ struct Vector2 {
Vector2 operator/(const real_t &rvalue) const;
void operator/=(const real_t &rvalue);
+ void operator/=(const Vector2 &rvalue) { *this = *this / rvalue; }
Vector2 operator-() const;
bool operator==(const Vector2 &p_vec2) const;
bool operator!=(const Vector2 &p_vec2) const;
- bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
- bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); }
+ bool operator<(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y < p_vec2.y) : (x < p_vec2.x); }
+ bool operator<=(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y <= p_vec2.y) : (x < p_vec2.x); }
real_t angle() const;
@@ -211,11 +213,11 @@ _FORCE_INLINE_ Vector2 Vector2::operator-() const {
_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const {
- return x == p_vec2.x && y == p_vec2.y;
+ return Math::is_equal_approx(x, p_vec2.x) && Math::is_equal_approx(y, p_vec2.y);
}
_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
- return x != p_vec2.x || y != p_vec2.y;
+ return !Math::is_equal_approx(x, p_vec2.x) || !Math::is_equal_approx(y, p_vec2.y);
}
Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const {
@@ -236,6 +238,12 @@ Vector2 Vector2::slerp(const Vector2 &p_b, real_t p_t) const {
return rotated(theta * p_t);
}
+Vector2 Vector2::direction_to(const Vector2 &p_b) const {
+ Vector2 ret(p_b.x - x, p_b.y - y);
+ ret.normalize();
+ return ret;
+}
+
Vector2 Vector2::linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t) {
Vector2 res = p_a;
diff --git a/core/math/vector3.h b/core/math/vector3.h
index b11838d16e..21fc09653f 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -112,6 +112,7 @@ struct Vector3 {
_FORCE_INLINE_ Vector3 project(const Vector3 &p_b) const;
_FORCE_INLINE_ real_t angle_to(const Vector3 &p_b) const;
+ _FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_b) const;
_FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const;
_FORCE_INLINE_ Vector3 bounce(const Vector3 &p_normal) const;
@@ -244,6 +245,12 @@ real_t Vector3::angle_to(const Vector3 &p_b) const {
return Math::atan2(cross(p_b).length(), dot(p_b));
}
+Vector3 Vector3::direction_to(const Vector3 &p_b) const {
+ Vector3 ret(p_b.x - x, p_b.y - y, p_b.z - z);
+ ret.normalize();
+ return ret;
+}
+
/* Operators */
Vector3 &Vector3::operator+=(const Vector3 &p_v) {
@@ -334,17 +341,17 @@ Vector3 Vector3::operator-() const {
bool Vector3::operator==(const Vector3 &p_v) const {
- return (x == p_v.x && y == p_v.y && z == p_v.z);
+ return (Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z));
}
bool Vector3::operator!=(const Vector3 &p_v) const {
- return (x != p_v.x || y != p_v.y || z != p_v.z);
+ return (!Math::is_equal_approx(x, p_v.x) || !Math::is_equal_approx(y, p_v.y) || !Math::is_equal_approx(z, p_v.z));
}
bool Vector3::operator<(const Vector3 &p_v) const {
- if (x == p_v.x) {
- if (y == p_v.y)
+ if (Math::is_equal_approx(x, p_v.x)) {
+ if (Math::is_equal_approx(y, p_v.y))
return z < p_v.z;
else
return y < p_v.y;
@@ -355,8 +362,8 @@ bool Vector3::operator<(const Vector3 &p_v) const {
bool Vector3::operator<=(const Vector3 &p_v) const {
- if (x == p_v.x) {
- if (y == p_v.y)
+ if (Math::is_equal_approx(x, p_v.x)) {
+ if (Math::is_equal_approx(y, p_v.y))
return z <= p_v.z;
else
return y < p_v.y;
@@ -395,13 +402,14 @@ real_t Vector3::length_squared() const {
void Vector3::normalize() {
- real_t l = length();
- if (l == 0) {
+ real_t lengthsq = length_squared();
+ if (lengthsq == 0) {
x = y = z = 0;
} else {
- x /= l;
- y /= l;
- z /= l;
+ real_t length = Math::sqrt(lengthsq);
+ x /= length;
+ y /= length;
+ z /= length;
}
}
diff --git a/core/message_queue.cpp b/core/message_queue.cpp
index c57bd4081c..32d2b805f6 100644
--- a/core/message_queue.cpp
+++ b/core/message_queue.cpp
@@ -58,7 +58,7 @@ Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, const V
Message *msg = memnew_placement(&buffer[buffer_end], Message);
msg->args = p_argcount;
- msg->instance_ID = p_id;
+ msg->instance_id = p_id;
msg->target = p_method;
msg->type = TYPE_CALL;
if (p_show_error)
@@ -109,7 +109,7 @@ Error MessageQueue::push_set(ObjectID p_id, const StringName &p_prop, const Vari
Message *msg = memnew_placement(&buffer[buffer_end], Message);
msg->args = 1;
- msg->instance_ID = p_id;
+ msg->instance_id = p_id;
msg->target = p_prop;
msg->type = TYPE_SET;
@@ -143,7 +143,7 @@ Error MessageQueue::push_notification(ObjectID p_id, int p_notification) {
Message *msg = memnew_placement(&buffer[buffer_end], Message);
msg->type = TYPE_NOTIFICATION;
- msg->instance_ID = p_id;
+ msg->instance_id = p_id;
//msg->target;
msg->notification = p_notification;
@@ -177,7 +177,7 @@ void MessageQueue::statistics() {
while (read_pos < buffer_end) {
Message *message = (Message *)&buffer[read_pos];
- Object *target = ObjectDB::get_instance(message->instance_ID);
+ Object *target = ObjectDB::get_instance(message->instance_id);
if (target != NULL) {
@@ -289,7 +289,7 @@ void MessageQueue::flush() {
_THREAD_SAFE_UNLOCK_
- Object *target = ObjectDB::get_instance(message->instance_ID);
+ Object *target = ObjectDB::get_instance(message->instance_id);
if (target != NULL) {
@@ -302,10 +302,6 @@ void MessageQueue::flush() {
_call_function(target, message->target, args, message->args, message->type & FLAG_SHOW_ERROR);
- for (int i = 0; i < message->args; i++) {
- args[i].~Variant();
- }
-
} break;
case TYPE_NOTIFICATION: {
@@ -319,11 +315,17 @@ void MessageQueue::flush() {
// messages don't expect a return value
target->set(message->target, *arg);
- arg->~Variant();
} break;
}
}
+ if ((message->type & FLAG_MASK) != TYPE_NOTIFICATION) {
+ Variant *args = (Variant *)(message + 1);
+ for (int i = 0; i < message->args; i++) {
+ args[i].~Variant();
+ }
+ }
+
message->~Message();
_THREAD_SAFE_LOCK_
diff --git a/core/message_queue.h b/core/message_queue.h
index 2515eb4a98..026d17ad3f 100644
--- a/core/message_queue.h
+++ b/core/message_queue.h
@@ -54,7 +54,7 @@ class MessageQueue {
struct Message {
- ObjectID instance_ID;
+ ObjectID instance_id;
StringName target;
int16_t type;
union {
diff --git a/core/method_bind.h b/core/method_bind.h
index 5ea8adb7e0..1b0c3b27c0 100644
--- a/core/method_bind.h
+++ b/core/method_bind.h
@@ -273,6 +273,8 @@ public:
void set_argument_names(const Vector<StringName> &p_names); //set by class, db, can't be inferred otherwise
Vector<StringName> get_argument_names() const;
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const = 0;
+
#endif
void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
@@ -329,6 +331,10 @@ public:
return _gen_argument_type_info(p_arg).type;
}
+ virtual GodotTypeInfo::Metadata get_argument_meta(int) const {
+ return GodotTypeInfo::METADATA_NONE;
+ }
+
#else
virtual Variant::Type _gen_argument_type(int p_arg) const {
diff --git a/core/object.cpp b/core/object.cpp
index 8b693f039c..64f55f08a9 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -608,18 +608,16 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co
}
bool valid = false;
- Variant current_value = get(p_names[0]);
+ Variant current_value = get(p_names[0], &valid);
for (int i = 1; i < p_names.size(); i++) {
current_value = current_value.get_named(p_names[i], &valid);
- if (!valid) {
- if (r_valid)
- *r_valid = false;
- return Variant();
- }
+ if (!valid)
+ break;
}
if (r_valid)
- *r_valid = true;
+ *r_valid = valid;
+
return current_value;
}
@@ -956,6 +954,16 @@ void Object::notification(int p_notification, bool p_reversed) {
}
}
+String Object::to_string() {
+ if (script_instance) {
+ bool valid;
+ String ret = script_instance->to_string(&valid);
+ if (valid)
+ return ret;
+ }
+ return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
+}
+
void Object::_changed_callback(Object *p_changed, const char *p_prop) {
}
@@ -1059,6 +1067,10 @@ Variant Object::get_meta(const String &p_name) const {
return metadata[p_name];
}
+void Object::remove_meta(const String &p_name) {
+ metadata.erase(p_name);
+}
+
Array Object::_get_property_list_bind() const {
List<PropertyInfo> lpi;
@@ -1366,7 +1378,10 @@ Array Object::_get_incoming_connections() const {
void Object::get_signal_list(List<MethodInfo> *p_signals) const {
if (!script.is_null()) {
- Ref<Script>(script)->get_script_signal_list(p_signals);
+ Ref<Script> scr = script;
+ if (scr.is_valid()) {
+ scr->get_script_signal_list(p_signals);
+ }
}
ClassDB::get_signal_list(get_class_name(), p_signals);
@@ -1637,7 +1652,8 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) {
_clear_internal_resource_paths(d[E->get()]);
}
} break;
- default: {}
+ default: {
+ }
}
}
@@ -1681,12 +1697,14 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);
ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);
ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("to_string"), &Object::to_string);
ClassDB::bind_method(D_METHOD("get_instance_id"), &Object::get_instance_id);
ClassDB::bind_method(D_METHOD("set_script", "script"), &Object::set_script);
ClassDB::bind_method(D_METHOD("get_script"), &Object::get_script);
ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta);
+ ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta);
ClassDB::bind_method(D_METHOD("get_meta", "name"), &Object::get_meta);
ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta);
ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind);
@@ -1767,6 +1785,7 @@ void Object::_bind_methods() {
#endif
BIND_VMETHOD(MethodInfo("_init"));
+ BIND_VMETHOD(MethodInfo(Variant::STRING, "_to_string"));
BIND_CONSTANT(NOTIFICATION_POSTINITIALIZE);
BIND_CONSTANT(NOTIFICATION_PREDELETE);
@@ -1938,8 +1957,8 @@ Object::Object() {
_class_ptr = NULL;
_block_signals = false;
_predelete_ok = 0;
- _instance_ID = 0;
- _instance_ID = ObjectDB::add_instance(this);
+ _instance_id = 0;
+ _instance_id = ObjectDB::add_instance(this);
_can_translate = true;
_is_queued_for_deletion = false;
instance_binding_count = 0;
@@ -1993,7 +2012,7 @@ Object::~Object() {
}
ObjectDB::remove_instance(this);
- _instance_ID = 0;
+ _instance_id = 0;
_predelete_ok = 2;
if (!ScriptServer::are_languages_finished()) {
@@ -2041,10 +2060,10 @@ void ObjectDB::remove_instance(Object *p_object) {
rw_lock->write_unlock();
}
-Object *ObjectDB::get_instance(ObjectID p_instance_ID) {
+Object *ObjectDB::get_instance(ObjectID p_instance_id) {
rw_lock->read_lock();
- Object **obj = instances.getptr(p_instance_ID);
+ Object **obj = instances.getptr(p_instance_id);
rw_lock->read_unlock();
if (!obj)
diff --git a/core/object.h b/core/object.h
index e8a6178052..4394c1c3da 100644
--- a/core/object.h
+++ b/core/object.h
@@ -88,6 +88,7 @@ enum PropertyHint {
PROPERTY_HINT_PROPERTY_OF_SCRIPT, ///< a property of a script & base
PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send
PROPERTY_HINT_NODE_PATH_VALID_TYPES,
+ PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -464,7 +465,7 @@ private:
bool _block_signals;
int _predelete_ok;
Set<Object *> change_receptors;
- ObjectID _instance_ID;
+ ObjectID _instance_id;
bool _predelete();
void _postinitialize();
bool _can_translate;
@@ -576,7 +577,7 @@ public:
bool _is_gpl_reversed() const { return false; }
- _FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_ID; }
+ _FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; }
// this is used for editors
void add_change_receptor(Object *p_receptor);
@@ -658,6 +659,7 @@ public:
void call_multilevel(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper
void notification(int p_notification, bool p_reversed = false);
+ String to_string();
//used mainly by script, get and set all INCLUDING string
virtual Variant getvar(const Variant &p_key, bool *r_valid = NULL) const;
@@ -672,6 +674,7 @@ public:
bool has_meta(const String &p_name) const;
void set_meta(const String &p_name, const Variant &p_value);
+ void remove_meta(const String &p_name);
Variant get_meta(const String &p_name) const;
void get_meta_list(List<String> *p_list) const;
@@ -774,7 +777,7 @@ class ObjectDB {
public:
typedef void (*DebugFunc)(Object *p_obj);
- static Object *get_instance(ObjectID p_instance_ID);
+ static Object *get_instance(ObjectID p_instance_id);
static void debug_objects(DebugFunc p_func);
static int get_object_count();
diff --git a/core/ordered_hash_map.h b/core/ordered_hash_map.h
index 09d43d6797..2c18de92be 100644
--- a/core/ordered_hash_map.h
+++ b/core/ordered_hash_map.h
@@ -274,6 +274,10 @@ public:
inline bool empty() const { return list.empty(); }
inline int size() const { return list.size(); }
+ const void *id() const {
+ return list.id();
+ }
+
void clear() {
map.clear();
list.clear();
diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp
index 2c1c655175..d81c30f33a 100644
--- a/core/os/dir_access.cpp
+++ b/core/os/dir_access.cpp
@@ -330,7 +330,7 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) {
if (err == OK && p_chmod_flags != -1) {
fdst->close();
- err = fdst->_chmod(p_to, p_chmod_flags);
+ err = FileAccess::set_unix_permissions(p_to, p_chmod_flags);
// If running on a platform with no chmod support (i.e., Windows), don't fail
if (err == ERR_UNAVAILABLE)
err = OK;
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index 39d9f45bd7..079f51bada 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -507,6 +507,29 @@ uint64_t FileAccess::get_modified_time(const String &p_file) {
return mt;
}
+uint32_t FileAccess::get_unix_permissions(const String &p_file) {
+
+ if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_file))
+ return 0;
+
+ FileAccess *fa = create_for_path(p_file);
+ ERR_FAIL_COND_V(!fa, 0);
+
+ uint32_t mt = fa->_get_unix_permissions(p_file);
+ memdelete(fa);
+ return mt;
+}
+
+Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+
+ FileAccess *fa = create_for_path(p_file);
+ ERR_FAIL_COND_V(!fa, ERR_CANT_CREATE);
+
+ Error err = fa->_set_unix_permissions(p_file, p_permissions);
+ memdelete(fa);
+ return err;
+}
+
void FileAccess::store_string(const String &p_string) {
if (p_string.length() == 0)
@@ -571,10 +594,16 @@ void FileAccess::store_buffer(const uint8_t *p_src, int p_length) {
store_8(p_src[i]);
}
-Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path) {
+Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) {
- FileAccess *f = FileAccess::open(p_path, READ);
- ERR_FAIL_COND_V(!f, Vector<uint8_t>());
+ FileAccess *f = FileAccess::open(p_path, READ, r_error);
+ if (!f) {
+ if (r_error) { // if error requested, do not throw error
+ return Vector<uint8_t>();
+ } else {
+ ERR_FAIL_COND_V(!f, Vector<uint8_t>());
+ }
+ }
Vector<uint8_t> data;
data.resize(f->get_len());
f->get_buffer(data.ptrw(), data.size());
@@ -582,6 +611,26 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path) {
return data;
}
+String FileAccess::get_file_as_string(const String &p_path, Error *r_error) {
+
+ Error err;
+ Vector<uint8_t> array = get_file_as_array(p_path, &err);
+ if (r_error) {
+ *r_error = err;
+ }
+ if (err != OK) {
+ if (r_error) {
+ return String();
+ } else {
+ ERR_FAIL_COND_V(err != OK, String());
+ }
+ }
+
+ String ret;
+ ret.parse_utf8((const char *)array.ptr(), array.size());
+ return ret;
+}
+
String FileAccess::get_md5(const String &p_file) {
FileAccess *f = FileAccess::open(p_file, READ);
diff --git a/core/os/file_access.h b/core/os/file_access.h
index c65b75369c..4930eae35a 100644
--- a/core/os/file_access.h
+++ b/core/os/file_access.h
@@ -56,6 +56,9 @@ public:
bool endian_swap;
bool real_is_double;
+ virtual uint32_t _get_unix_permissions(const String &p_file) = 0;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0;
+
protected:
String fix_path(const String &p_path) const;
virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file
@@ -148,14 +151,14 @@ public:
virtual Error reopen(const String &p_path, int p_mode_flags); ///< does not change the AccessType
- virtual Error _chmod(const String &p_path, int p_mod) { return ERR_UNAVAILABLE; }
-
static FileAccess *create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static FileAccess *create_for_path(const String &p_path);
static FileAccess *open(const String &p_path, int p_mode_flags, Error *r_error = NULL); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static CreateFunc get_create_func(AccessType p_access);
static bool exists(const String &p_name); ///< return true if a file exists
static uint64_t get_modified_time(const String &p_file);
+ static uint32_t get_unix_permissions(const String &p_file);
+ static Error set_unix_permissions(const String &p_file, uint32_t p_permissions);
static void set_backup_save(bool p_enable) { backup_save = p_enable; };
static bool is_backup_save_enabled() { return backup_save; };
@@ -164,7 +167,8 @@ public:
static String get_sha256(const String &p_file);
static String get_multiple_md5(const Vector<String> &p_file);
- static Vector<uint8_t> get_file_as_array(const String &p_path);
+ static Vector<uint8_t> get_file_as_array(const String &p_path, Error *r_error = NULL);
+ static String get_file_as_string(const String &p_path, Error *r_error = NULL);
template <class T>
static void make_default(AccessType p_access) {
diff --git a/core/os/input.cpp b/core/os/input.cpp
index caa9fb1493..f04d4a1b3e 100644
--- a/core/os/input.cpp
+++ b/core/os/input.cpp
@@ -34,6 +34,10 @@
#include "core/os/os.h"
#include "core/project_settings.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif
+
Input *Input::singleton = NULL;
Input *Input::get_singleton() {
@@ -89,6 +93,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
+ ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &Input::get_current_cursor_shape);
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);
@@ -122,6 +127,8 @@ void Input::_bind_methods() {
void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
#ifdef TOOLS_ENABLED
+ const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
+
String pf = p_function;
if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength")) {
@@ -135,7 +142,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
continue;
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
- r_options->push_back("\"" + name + "\"");
+ r_options->push_back(quote_style + name + quote_style);
}
}
#endif
diff --git a/core/os/input.h b/core/os/input.h
index c8b80b28d0..de04f239e6 100644
--- a/core/os/input.h
+++ b/core/os/input.h
@@ -121,10 +121,10 @@ public:
virtual bool is_emulating_touch_from_mouse() const = 0;
virtual bool is_emulating_mouse_from_touch() const = 0;
- virtual CursorShape get_default_cursor_shape() = 0;
+ virtual CursorShape get_default_cursor_shape() const = 0;
virtual void set_default_cursor_shape(CursorShape p_shape) = 0;
+ virtual CursorShape get_current_cursor_shape() const = 0;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0;
- virtual void set_mouse_in_window(bool p_in_window) = 0;
virtual String get_joy_button_string(int p_button) = 0;
virtual String get_joy_axis_string(int p_axis) = 0;
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index 25a5c2afeb..a072017353 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -717,8 +717,17 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *
bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false;
if (p_pressed != NULL)
*p_pressed = pressed;
- if (p_strength != NULL)
- *p_strength = pressed ? CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f) : 0.0f;
+ if (p_strength != NULL) {
+ if (pressed) {
+ if (p_deadzone == 1.0f) {
+ *p_strength = 1.0f;
+ } else {
+ *p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f);
+ }
+ } else {
+ *p_strength = 0.0f;
+ }
+ }
}
return match;
}
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index bfdf92acfa..ad734d3fc8 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -51,21 +51,19 @@ protected:
public:
enum {
- NOTIFICATION_WM_MOUSE_ENTER = 2,
- NOTIFICATION_WM_MOUSE_EXIT = 3,
- NOTIFICATION_WM_FOCUS_IN = 4,
- NOTIFICATION_WM_FOCUS_OUT = 5,
- NOTIFICATION_WM_QUIT_REQUEST = 6,
- NOTIFICATION_WM_GO_BACK_REQUEST = 7,
- NOTIFICATION_WM_UNFOCUS_REQUEST = 8,
- NOTIFICATION_OS_MEMORY_WARNING = 9,
- // Note: NOTIFICATION_TRANSLATION_CHANGED and NOTIFICATION_WM_ABOUT used to have id=10 and id=11 but these
- // conflict with NOTIFICATION_ENTER_TREE (id=10) and NOTIFICATION_EXIT_TREE (id=11), so id=90 and id=91
- // fixes this issue.
- NOTIFICATION_TRANSLATION_CHANGED = 90,
- NOTIFICATION_WM_ABOUT = 91,
- NOTIFICATION_CRASH = 92,
- NOTIFICATION_OS_IME_UPDATE = 93,
+ //make sure these are replicated in Node
+ NOTIFICATION_WM_MOUSE_ENTER = 1002,
+ NOTIFICATION_WM_MOUSE_EXIT = 1003,
+ NOTIFICATION_WM_FOCUS_IN = 1004,
+ NOTIFICATION_WM_FOCUS_OUT = 1005,
+ NOTIFICATION_WM_QUIT_REQUEST = 1006,
+ NOTIFICATION_WM_GO_BACK_REQUEST = 1007,
+ NOTIFICATION_WM_UNFOCUS_REQUEST = 1008,
+ NOTIFICATION_OS_MEMORY_WARNING = 1009,
+ NOTIFICATION_TRANSLATION_CHANGED = 1010,
+ NOTIFICATION_WM_ABOUT = 1011,
+ NOTIFICATION_CRASH = 1012,
+ NOTIFICATION_OS_IME_UPDATE = 1013,
};
virtual void input_event(const Ref<InputEvent> &p_event);
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp
index 0d7ad23d68..7cb7ae130f 100644
--- a/core/os/midi_driver.cpp
+++ b/core/os/midi_driver.cpp
@@ -75,6 +75,11 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_
if (length >= 3) {
event->set_pitch(data[1]);
event->set_velocity(data[2]);
+
+ if (event->get_message() == MIDI_MESSAGE_NOTE_ON && event->get_velocity() == 0) {
+ // https://www.midi.org/forum/228-writing-midi-software-send-note-off,-or-zero-velocity-note-on
+ event->set_message(MIDI_MESSAGE_NOTE_OFF);
+ }
}
break;
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 03e63f636e..1a3c9ac5f8 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -220,6 +220,16 @@ int OS::get_virtual_keyboard_height() const {
return 0;
}
+void OS::set_cursor_shape(CursorShape p_shape) {
+}
+
+OS::CursorShape OS::get_cursor_shape() const {
+ return CURSOR_ARROW;
+}
+
+void OS::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+}
+
void OS::print_all_resources(String p_to_file) {
ERR_FAIL_COND(p_to_file != "" && _OSPRF);
@@ -455,6 +465,9 @@ void OS::_ensure_user_data_dir() {
memdelete(da);
}
+void OS::set_native_icon(const String &p_filename) {
+}
+
void OS::set_icon(const Ref<Image> &p_icon) {
}
diff --git a/core/os/os.h b/core/os/os.h
index d02d5a2c84..4f6a539e78 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -45,6 +45,8 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
+class Mutex;
+
class OS {
static OS *singleton;
@@ -260,7 +262,7 @@ public:
virtual int get_low_processor_usage_mode_sleep_usec() const;
virtual String get_executable_path() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false) = 0;
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL) = 0;
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
@@ -271,7 +273,7 @@ public:
virtual String get_environment(const String &p_var) const = 0;
virtual bool set_environment(const String &p_var, const String &p_value) const = 0;
- virtual String get_name() = 0;
+ virtual String get_name() const = 0;
virtual List<String> get_cmdline_args() const { return _cmdline; }
virtual String get_model_name() const;
@@ -377,8 +379,9 @@ public:
// returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
virtual int get_virtual_keyboard_height() const;
- virtual void set_cursor_shape(CursorShape p_shape) = 0;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) = 0;
+ virtual void set_cursor_shape(CursorShape p_shape);
+ virtual CursorShape get_cursor_shape() const;
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual bool get_swap_ok_cancel() { return false; }
virtual void dump_memory_to_file(const char *p_file);
@@ -448,6 +451,7 @@ public:
virtual void make_rendering_thread();
virtual void swap_buffers();
+ virtual void set_native_icon(const String &p_filename);
virtual void set_icon(const Ref<Image> &p_icon);
virtual int get_exit_code() const;
diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp
index 6c17f42b13..fa60be64a7 100644
--- a/core/packed_data_container.cpp
+++ b/core/packed_data_container.cpp
@@ -114,7 +114,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b
} else {
Variant v;
- Error rerr = decode_variant(v, p_buf + p_ofs, datalen - p_ofs, NULL);
+ Error rerr = decode_variant(v, p_buf + p_ofs, datalen - p_ofs, NULL, false);
if (rerr != OK) {
@@ -249,9 +249,9 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd
uint32_t pos = tmpdata.size();
int len;
- encode_variant(p_data, NULL, len);
+ encode_variant(p_data, NULL, len, false);
tmpdata.resize(tmpdata.size() + len);
- encode_variant(p_data, &tmpdata.write[pos], len);
+ encode_variant(p_data, &tmpdata.write[pos], len, false);
return pos;
} break;
@@ -319,7 +319,8 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd
} break;
- default: {}
+ default: {
+ }
}
return OK;
diff --git a/core/print_string.cpp b/core/print_string.cpp
index d91d49f53b..3271744af3 100644
--- a/core/print_string.cpp
+++ b/core/print_string.cpp
@@ -68,8 +68,8 @@ void remove_print_handler(PrintHandlerList *p_handler) {
}
//OS::get_singleton()->print("print handler list is %p\n",print_handler_list);
- ERR_FAIL_COND(l == NULL);
_global_unlock();
+ ERR_FAIL_COND(l == NULL);
}
void print_line(String p_string) {
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 02c7c9e029..4c37142ffd 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -75,11 +75,19 @@ String ProjectSettings::localize_path(const String &p_path) const {
memdelete(dir);
- if (!cwd.begins_with(resource_path)) {
+ // Ensure that we end with a '/'.
+ // This is important to ensure that we do not wrongly localize the resource path
+ // in an absolute path that just happens to contain this string but points to a
+ // different folder (e.g. "/my/project" as resource_path would be contained in
+ // "/my/project_data", even though the latter is not part of res://.
+ // `plus_file("")` is an easy way to ensure we have a trailing '/'.
+ const String res_path = resource_path.plus_file("");
+
+ if (!cwd.begins_with(res_path)) {
return p_path;
};
- return cwd.replace_first(resource_path, "res:/");
+ return cwd.replace_first(res_path, "res://");
} else {
memdelete(dir);
@@ -501,7 +509,7 @@ Error ProjectSettings::_load_settings_binary(const String p_path) {
d.resize(vlen);
f->get_buffer(d.ptrw(), vlen);
Variant value;
- err = decode_variant(value, d.ptr(), d.size());
+ err = decode_variant(value, d.ptr(), d.size(), NULL, true);
ERR_EXPLAIN("Error decoding property: " + key);
ERR_CONTINUE(err != OK);
set(key, value);
@@ -656,7 +664,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
file->store_string(key);
int len;
- err = encode_variant(p_custom_features, NULL, len);
+ err = encode_variant(p_custom_features, NULL, len, false);
if (err != OK) {
memdelete(file);
ERR_FAIL_V(err);
@@ -665,7 +673,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
Vector<uint8_t> buff;
buff.resize(len);
- err = encode_variant(p_custom_features, buff.ptrw(), len);
+ err = encode_variant(p_custom_features, buff.ptrw(), len, false);
if (err != OK) {
memdelete(file);
ERR_FAIL_V(err);
@@ -694,7 +702,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
file->store_string(key);
int len;
- err = encode_variant(value, NULL, len);
+ err = encode_variant(value, NULL, len, true);
if (err != OK)
memdelete(file);
ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA);
@@ -702,7 +710,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
Vector<uint8_t> buff;
buff.resize(len);
- err = encode_variant(value, buff.ptrw(), len);
+ err = encode_variant(value, buff.ptrw(), len, true);
if (err != OK)
memdelete(file);
ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA);
@@ -1004,6 +1012,17 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/use_custom_user_dir", false);
GLOBAL_DEF("application/config/custom_user_dir_name", "");
GLOBAL_DEF("application/config/project_settings_override", "");
+ GLOBAL_DEF("audio/default_bus_layout", "res://default_bus_layout.tres");
+ custom_prop_info["audio/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
+
+ PoolStringArray extensions = PoolStringArray();
+ extensions.push_back("gd");
+ if (Engine::get_singleton()->has_singleton("GodotSharp"))
+ extensions.push_back("cs");
+ extensions.push_back("shader");
+
+ GLOBAL_DEF("editor/search_in_file_extensions", extensions);
+ custom_prop_info["editor/search_in_file_extensions"] = PropertyInfo(Variant::POOL_STRING_ARRAY, "editor/search_in_file_extensions");
action = Dictionary();
action["deadzone"] = Variant(0.5f);
diff --git a/core/reference.h b/core/reference.h
index f3fcc922c7..8a19f846c7 100644
--- a/core/reference.h
+++ b/core/reference.h
@@ -197,6 +197,19 @@ public:
r.reference = NULL;
}
+ template <class T_Other>
+ void reference_ptr(T_Other *p_ptr) {
+ if (reference == p_ptr) {
+ return;
+ }
+ unref();
+
+ T *r = Object::cast_to<T>(p_ptr);
+ if (r) {
+ ref_pointer(r);
+ }
+ }
+
Ref(const Ref &p_from) {
reference = NULL;
@@ -362,7 +375,8 @@ struct PtrToArg<const RefPtr &> {
template <class T>
struct GetTypeInfo<Ref<T> > {
- enum { VARIANT_TYPE = Variant::OBJECT };
+ static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
@@ -371,7 +385,8 @@ struct GetTypeInfo<Ref<T> > {
template <class T>
struct GetTypeInfo<const Ref<T> &> {
- enum { VARIANT_TYPE = Variant::OBJECT };
+ static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
diff --git a/core/resource.cpp b/core/resource.cpp
index 74c93cd790..74e2c1ed6b 100644
--- a/core/resource.cpp
+++ b/core/resource.cpp
@@ -363,6 +363,26 @@ bool Resource::is_translation_remapped() const {
return remapped_list.in_list();
}
+#ifdef TOOLS_ENABLED
+//helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored
+void Resource::set_id_for_path(const String &p_path, int p_id) {
+ if (p_id == -1) {
+ id_for_path.erase(p_path);
+ } else {
+ id_for_path[p_path] = p_id;
+ }
+}
+
+int Resource::get_id_for_path(const String &p_path) const {
+
+ if (id_for_path.has(p_path)) {
+ return id_for_path[p_path];
+ } else {
+ return -1;
+ }
+}
+#endif
+
void Resource::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_path", "path"), &Resource::_set_path);
diff --git a/core/resource.h b/core/resource.h
index a4d9e998ac..853b2859c7 100644
--- a/core/resource.h
+++ b/core/resource.h
@@ -88,7 +88,9 @@ protected:
void _set_path(const String &p_path);
void _take_over_path(const String &p_path);
-
+#ifdef TOOLS_ENABLED
+ Map<String, int> id_for_path;
+#endif
public:
static Node *(*_get_local_scene_func)(); //used by editor
@@ -137,6 +139,12 @@ public:
virtual RID get_rid() const; // some resources may offer conversion to RID
+#ifdef TOOLS_ENABLED
+ //helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored
+ void set_id_for_path(const String &p_path, int p_id);
+ int get_id_for_path(const String &p_path) const;
+#endif
+
Resource();
~Resource();
};
diff --git a/core/script_language.cpp b/core/script_language.cpp
index 4a6f904f9d..97758ced66 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -30,6 +30,7 @@
#include "script_language.h"
+#include "core/core_string_names.h"
#include "core/project_settings.h"
ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
diff --git a/core/script_language.h b/core/script_language.h
index b6d7bea9c7..b2dab666c4 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -173,6 +173,11 @@ public:
virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
virtual void notification(int p_notification) = 0;
+ virtual String to_string(bool *r_valid) {
+ if (r_valid)
+ *r_valid = false;
+ return String();
+ }
//this is used by script languages that keep a reference counter of their own
//you can make make Ref<> not die when it reaches zero, so deleting the reference
@@ -205,6 +210,8 @@ public:
static ScriptCodeCompletionCache *get_singleton() { return singleton; }
ScriptCodeCompletionCache();
+
+ virtual ~ScriptCodeCompletionCache() {}
};
class ScriptLanguage {
diff --git a/core/string_builder.h b/core/string_builder.h
index 40d70e8f45..0c4985d230 100644
--- a/core/string_builder.h
+++ b/core/string_builder.h
@@ -70,6 +70,10 @@ public:
return appended_strings.size();
}
+ _FORCE_INLINE_ uint32_t get_string_length() const {
+ return string_length;
+ }
+
String as_string() const;
_FORCE_INLINE_ operator String() const {
diff --git a/core/translation.cpp b/core/translation.cpp
index 6921f1d9f1..0b55badc61 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -179,6 +179,7 @@ static const char *locale_list[] = {
"ff_SN", // Fulah (Senegal)
"fi", // Finnish
"fi_FI", // Finnish (Finland)
+ "fil", // Filipino
"fil_PH", // Filipino (Philippines)
"fo_FO", // Faroese (Faroe Islands)
"fr", // French
@@ -227,6 +228,7 @@ static const char *locale_list[] = {
"ja", // Japanese
"ja_JP", // Japanese (Japan)
"kab_DZ", // Kabyle (Algeria)
+ "ka", // Georgian
"ka_GE", // Georgian (Georgia)
"kk_KZ", // Kazakh (Kazakhstan)
"kl_GL", // Kalaallisut (Greenland)
@@ -257,10 +259,12 @@ static const char *locale_list[] = {
"mg_MG", // Malagasy (Madagascar)
"mh_MH", // Marshallese (Marshall Islands)
"mhr_RU", // Eastern Mari (Russia)
- "mi_NZ", // Maori (New Zealand)
+ "mi", // Māori
+ "mi_NZ", // Māori (New Zealand)
"miq_NI", // Mískito (Nicaragua)
"mk", // Macedonian
"mk_MK", // Macedonian (Macedonia)
+ "ml", // Malayalam
"ml_IN", // Malayalam (India)
"mni_IN", // Manipuri (India)
"mn_MN", // Mongolian (Mongolia)
@@ -326,6 +330,7 @@ static const char *locale_list[] = {
"sgs_LT", // Samogitian (Lithuania)
"shs_CA", // Shuswap (Canada)
"sid_ET", // Sidamo (Ethiopia)
+ "si", // Sinhala
"si_LK", // Sinhala (Sri Lanka)
"sk", // Slovak
"sk_SK", // Slovak (Slovakia)
@@ -343,6 +348,7 @@ static const char *locale_list[] = {
"sq_MK", // Albanian (Macedonia)
"sr", // Serbian
"sr_Cyrl", // Serbian (Cyrillic)
+ "sr_Latn", // Serbian (Latin)
"sr_ME", // Serbian (Montenegro)
"sr_RS", // Serbian (Serbia)
"ss_ZA", // Swati (South Africa)
@@ -357,6 +363,7 @@ static const char *locale_list[] = {
"ta_IN", // Tamil (India)
"ta_LK", // Tamil (Sri Lanka)
"tcy_IN", // Tulu (India)
+ "te", // Telugu
"te_IN", // Telugu (India)
"tg_TJ", // Tajik (Tajikistan)
"the_NP", // Chitwania Tharu (Nepal)
@@ -540,6 +547,7 @@ static const char *locale_names[] = {
"Fulah (Senegal)",
"Finnish",
"Finnish (Finland)",
+ "Filipino",
"Filipino (Philippines)",
"Faroese (Faroe Islands)",
"French",
@@ -588,6 +596,7 @@ static const char *locale_names[] = {
"Japanese",
"Japanese (Japan)",
"Kabyle (Algeria)",
+ "Georgian",
"Georgian (Georgia)",
"Kazakh (Kazakhstan)",
"Kalaallisut (Greenland)",
@@ -618,10 +627,12 @@ static const char *locale_names[] = {
"Malagasy (Madagascar)",
"Marshallese (Marshall Islands)",
"Eastern Mari (Russia)",
- "Maori (New Zealand)",
+ "Māori",
+ "Māori (New Zealand)",
"Mískito (Nicaragua)",
"Macedonian",
"Macedonian (Macedonia)",
+ "Malayalam",
"Malayalam (India)",
"Manipuri (India)",
"Mongolian (Mongolia)",
@@ -687,6 +698,7 @@ static const char *locale_names[] = {
"Samogitian (Lithuania)",
"Shuswap (Canada)",
"Sidamo (Ethiopia)",
+ "Sinhala",
"Sinhala (Sri Lanka)",
"Slovak",
"Slovak (Slovakia)",
@@ -704,6 +716,7 @@ static const char *locale_names[] = {
"Albanian (Macedonia)",
"Serbian",
"Serbian (Cyrillic)",
+ "Serbian (Latin)",
"Serbian (Montenegro)",
"Serbian (Serbia)",
"Swati (South Africa)",
@@ -718,6 +731,7 @@ static const char *locale_names[] = {
"Tamil (India)",
"Tamil (Sri Lanka)",
"Tulu (India)",
+ "Telugu",
"Telugu (India)",
"Tajik (Tajikistan)",
"Chitwania Tharu (Nepal)",
@@ -968,6 +982,19 @@ String TranslationServer::get_locale_name(const String &p_locale) const {
return locale_name_map[p_locale];
}
+Array TranslationServer::get_loaded_locales() const {
+ Array locales;
+ for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) {
+
+ const Ref<Translation> &t = E->get();
+ String l = t->get_locale();
+
+ locales.push_back(l);
+ }
+
+ return locales;
+}
+
Vector<String> TranslationServer::get_all_locales() {
Vector<String> locales;
@@ -1168,6 +1195,8 @@ void TranslationServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_translation", "translation"), &TranslationServer::remove_translation);
ClassDB::bind_method(D_METHOD("clear"), &TranslationServer::clear);
+
+ ClassDB::bind_method(D_METHOD("get_loaded_locales"), &TranslationServer::get_loaded_locales);
}
void TranslationServer::load_translations() {
diff --git a/core/translation.h b/core/translation.h
index b12bad0d72..d172b9ecf2 100644
--- a/core/translation.h
+++ b/core/translation.h
@@ -94,6 +94,8 @@ public:
String get_locale_name(const String &p_locale) const;
+ Array get_loaded_locales() const;
+
void add_translation(const Ref<Translation> &p_translation);
void remove_translation(const Ref<Translation> &p_translation);
diff --git a/core/type_info.h b/core/type_info.h
index c38688fea1..d85a63ee42 100644
--- a/core/type_info.h
+++ b/core/type_info.h
@@ -67,43 +67,80 @@ struct TypeInherits {
!TypesAreSame<B volatile const, void volatile const>::value;
};
+namespace GodotTypeInfo {
+enum Metadata {
+ METADATA_NONE,
+ METADATA_INT_IS_INT8,
+ METADATA_INT_IS_INT16,
+ METADATA_INT_IS_INT32,
+ METADATA_INT_IS_INT64,
+ METADATA_INT_IS_UINT8,
+ METADATA_INT_IS_UINT16,
+ METADATA_INT_IS_UINT32,
+ METADATA_INT_IS_UINT64,
+ METADATA_REAL_IS_FLOAT,
+ METADATA_REAL_IS_DOUBLE
+};
+}
+
template <class T, typename = void>
struct GetTypeInfo {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
ERR_PRINT("GetTypeInfo fallback. Bug!");
return PropertyInfo(); // Not "Nil", this is an error
}
};
-#define MAKE_TYPE_INFO(m_type, m_var_type) \
- template <> \
- struct GetTypeInfo<m_type> { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
- }; \
- template <> \
- struct GetTypeInfo<const m_type &> { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
+#define MAKE_TYPE_INFO(m_type, m_var_type) \
+ template <> \
+ struct GetTypeInfo<m_type> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_type &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ };
+
+#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \
+ template <> \
+ struct GetTypeInfo<m_type> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = m_metadata; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_type &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = m_metadata; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
};
MAKE_TYPE_INFO(bool, Variant::BOOL)
-MAKE_TYPE_INFO(uint8_t, Variant::INT)
-MAKE_TYPE_INFO(int8_t, Variant::INT)
-MAKE_TYPE_INFO(uint16_t, Variant::INT)
-MAKE_TYPE_INFO(int16_t, Variant::INT)
-MAKE_TYPE_INFO(uint32_t, Variant::INT)
-MAKE_TYPE_INFO(int32_t, Variant::INT)
-MAKE_TYPE_INFO(int64_t, Variant::INT)
-MAKE_TYPE_INFO(uint64_t, Variant::INT)
+MAKE_TYPE_INFO_WITH_META(uint8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT8)
+MAKE_TYPE_INFO_WITH_META(int8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT8)
+MAKE_TYPE_INFO_WITH_META(uint16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT16)
+MAKE_TYPE_INFO_WITH_META(int16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT16)
+MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT32)
+MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32)
+MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64)
+MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64)
MAKE_TYPE_INFO(wchar_t, Variant::INT)
-MAKE_TYPE_INFO(float, Variant::REAL)
-MAKE_TYPE_INFO(double, Variant::REAL)
+MAKE_TYPE_INFO_WITH_META(float, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_FLOAT)
+MAKE_TYPE_INFO_WITH_META(double, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_DOUBLE)
MAKE_TYPE_INFO(String, Variant::STRING)
MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
@@ -138,6 +175,7 @@ MAKE_TYPE_INFO(BSP_Tree, Variant::DICTIONARY)
template <>
struct GetTypeInfo<RefPtr> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
}
@@ -145,6 +183,7 @@ struct GetTypeInfo<RefPtr> {
template <>
struct GetTypeInfo<const RefPtr &> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
}
@@ -154,6 +193,7 @@ struct GetTypeInfo<const RefPtr &> {
template <>
struct GetTypeInfo<Variant> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
@@ -162,25 +202,28 @@ struct GetTypeInfo<Variant> {
template <>
struct GetTypeInfo<const Variant &> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
};
-#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \
- template <> \
- struct GetTypeInfo<m_template<m_type> > { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
- }; \
- template <> \
- struct GetTypeInfo<const m_template<m_type> &> { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
+#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \
+ template <> \
+ struct GetTypeInfo<m_template<m_type> > { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_template<m_type> &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
};
MAKE_TEMPLATE_TYPE_INFO(Vector, uint8_t, Variant::POOL_BYTE_ARRAY)
@@ -202,6 +245,7 @@ MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY)
template <typename T>
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(StringName(T::get_class_static()));
}
@@ -210,6 +254,7 @@ struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type>
template <typename T>
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(StringName(T::get_class_static()));
}
@@ -219,6 +264,7 @@ struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>:
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, String(#m_enum).replace("::", ".")); \
} \
diff --git a/core/typedefs.h b/core/typedefs.h
index 78688ff311..660139b90a 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -328,4 +328,31 @@ struct _GlobalLock {
#define _PRINTF_FORMAT_ATTRIBUTE_2_3
#endif
+/** This is needed due to a strange OpenGL API that expects a pointer
+ * type for an argument that is actually an offset.
+ */
+#define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr))
+
+/** Hint for compilers that this fallthrough in a switch is intentional.
+ * Can be replaced by [[fallthrough]] annotation if we move to C++17.
+ * Including conditional support for it for people who set -std=c++17
+ * themselves.
+ * Requires a trailing semicolon when used.
+ */
+#if __cplusplus >= 201703L
+#define FALLTHROUGH [[fallthrough]]
+#elif defined(__GNUC__) && __GNUC__ >= 7
+#define FALLTHROUGH __attribute__((fallthrough))
+#elif defined(__llvm__) && __cplusplus >= 201103L && defined(__has_feature)
+#if __has_feature(cxx_attributes) && defined(__has_warning)
+#if __has_warning("-Wimplicit-fallthrough")
+#define FALLTHROUGH [[clang::fallthrough]]
+#endif
+#endif
+#endif
+
+#ifndef FALLTHROUGH
+#define FALLTHROUGH
+#endif
+
#endif // TYPEDEFS_H
diff --git a/core/ucaps.h b/core/ucaps.h
index 5dd81296dd..ae5729a53d 100644
--- a/core/ucaps.h
+++ b/core/ucaps.h
@@ -704,672 +704,672 @@ static const int caps_table[CAPS_LEN][2] = {
};
static const int reverse_caps_table[CAPS_LEN - 1][2] = {
- { 0x41, 0x61 },
- { 0x42, 0x62 },
- { 0x43, 0x63 },
- { 0x44, 0x64 },
- { 0x45, 0x65 },
- { 0x46, 0x66 },
- { 0x47, 0x67 },
- { 0x48, 0x68 },
- { 0x49, 0x69 },
- { 0x4a, 0x6a },
- { 0x4b, 0x6b },
- { 0x4c, 0x6c },
- { 0x4d, 0x6d },
- { 0x4e, 0x6e },
- { 0x4f, 0x6f },
- { 0x50, 0x70 },
- { 0x51, 0x71 },
- { 0x52, 0x72 },
- { 0x53, 0x73 },
- { 0x54, 0x74 },
- { 0x55, 0x75 },
- { 0x56, 0x76 },
- { 0x57, 0x77 },
- { 0x58, 0x78 },
- { 0x59, 0x79 },
- { 0x5a, 0x7a },
- { 0xc0, 0xe0 },
- { 0xc1, 0xe1 },
- { 0xc2, 0xe2 },
- { 0xc3, 0xe3 },
- { 0xc4, 0xe4 },
- { 0xc5, 0xe5 },
- { 0xc6, 0xe6 },
- { 0xc7, 0xe7 },
- { 0xc8, 0xe8 },
- { 0xc9, 0xe9 },
- { 0xca, 0xea },
- { 0xcb, 0xeb },
- { 0xcc, 0xec },
- { 0xcd, 0xed },
- { 0xce, 0xee },
- { 0xcf, 0xef },
- { 0xd0, 0xf0 },
- { 0xd1, 0xf1 },
- { 0xd2, 0xf2 },
- { 0xd3, 0xf3 },
- { 0xd4, 0xf4 },
- { 0xd5, 0xf5 },
- { 0xd6, 0xf6 },
- { 0xd8, 0xf8 },
- { 0xd9, 0xf9 },
- { 0xda, 0xfa },
- { 0xdb, 0xfb },
- { 0xdc, 0xfc },
- { 0xdd, 0xfd },
- { 0xde, 0xfe },
- { 0x178, 0xff },
- { 0x100, 0x101 },
- { 0x102, 0x103 },
- { 0x104, 0x105 },
- { 0x106, 0x107 },
- { 0x108, 0x109 },
- { 0x10a, 0x10b },
- { 0x10c, 0x10d },
- { 0x10e, 0x10f },
- { 0x110, 0x111 },
- { 0x112, 0x113 },
- { 0x114, 0x115 },
- { 0x116, 0x117 },
- { 0x118, 0x119 },
- { 0x11a, 0x11b },
- { 0x11c, 0x11d },
- { 0x11e, 0x11f },
- { 0x120, 0x121 },
- { 0x122, 0x123 },
- { 0x124, 0x125 },
- { 0x126, 0x127 },
- { 0x128, 0x129 },
- { 0x12a, 0x12b },
- { 0x12c, 0x12d },
- { 0x12e, 0x12f },
- //{0x49,0x131},
- { 0x132, 0x133 },
- { 0x134, 0x135 },
- { 0x136, 0x137 },
- { 0x139, 0x13a },
- { 0x13b, 0x13c },
- { 0x13d, 0x13e },
- { 0x13f, 0x140 },
- { 0x141, 0x142 },
- { 0x143, 0x144 },
- { 0x145, 0x146 },
- { 0x147, 0x148 },
- { 0x14a, 0x14b },
- { 0x14c, 0x14d },
- { 0x14e, 0x14f },
- { 0x150, 0x151 },
- { 0x152, 0x153 },
- { 0x154, 0x155 },
- { 0x156, 0x157 },
- { 0x158, 0x159 },
- { 0x15a, 0x15b },
- { 0x15c, 0x15d },
- { 0x15e, 0x15f },
- { 0x160, 0x161 },
- { 0x162, 0x163 },
- { 0x164, 0x165 },
- { 0x166, 0x167 },
- { 0x168, 0x169 },
- { 0x16a, 0x16b },
- { 0x16c, 0x16d },
- { 0x16e, 0x16f },
- { 0x170, 0x171 },
- { 0x172, 0x173 },
- { 0x174, 0x175 },
- { 0x176, 0x177 },
- { 0x179, 0x17a },
- { 0x17b, 0x17c },
- { 0x17d, 0x17e },
- { 0x182, 0x183 },
- { 0x184, 0x185 },
- { 0x187, 0x188 },
- { 0x18b, 0x18c },
- { 0x191, 0x192 },
- { 0x198, 0x199 },
- { 0x1a0, 0x1a1 },
- { 0x1a2, 0x1a3 },
- { 0x1a4, 0x1a5 },
- { 0x1a7, 0x1a8 },
- { 0x1ac, 0x1ad },
- { 0x1af, 0x1b0 },
- { 0x1b3, 0x1b4 },
- { 0x1b5, 0x1b6 },
- { 0x1b8, 0x1b9 },
- { 0x1bc, 0x1bd },
- { 0x1c4, 0x1c6 },
- { 0x1c7, 0x1c9 },
- { 0x1ca, 0x1cc },
- { 0x1cd, 0x1ce },
- { 0x1cf, 0x1d0 },
- { 0x1d1, 0x1d2 },
- { 0x1d3, 0x1d4 },
- { 0x1d5, 0x1d6 },
- { 0x1d7, 0x1d8 },
- { 0x1d9, 0x1da },
- { 0x1db, 0x1dc },
- { 0x1de, 0x1df },
- { 0x1e0, 0x1e1 },
- { 0x1e2, 0x1e3 },
- { 0x1e4, 0x1e5 },
- { 0x1e6, 0x1e7 },
- { 0x1e8, 0x1e9 },
- { 0x1ea, 0x1eb },
- { 0x1ec, 0x1ed },
- { 0x1ee, 0x1ef },
- { 0x1f1, 0x1f3 },
- { 0x1f4, 0x1f5 },
- { 0x1fa, 0x1fb },
- { 0x1fc, 0x1fd },
- { 0x1fe, 0x1ff },
- { 0x200, 0x201 },
- { 0x202, 0x203 },
- { 0x204, 0x205 },
- { 0x206, 0x207 },
- { 0x208, 0x209 },
- { 0x20a, 0x20b },
- { 0x20c, 0x20d },
- { 0x20e, 0x20f },
- { 0x210, 0x211 },
- { 0x212, 0x213 },
- { 0x214, 0x215 },
- { 0x216, 0x217 },
- { 0x181, 0x253 },
- { 0x186, 0x254 },
- { 0x18a, 0x257 },
- { 0x18e, 0x258 },
- { 0x18f, 0x259 },
- { 0x190, 0x25b },
- { 0x193, 0x260 },
- { 0x194, 0x263 },
- { 0x197, 0x268 },
- { 0x196, 0x269 },
- { 0x19c, 0x26f },
- { 0x19d, 0x272 },
- { 0x19f, 0x275 },
- { 0x1a9, 0x283 },
- { 0x1ae, 0x288 },
- { 0x1b1, 0x28a },
- { 0x1b2, 0x28b },
- { 0x1b7, 0x292 },
- { 0x386, 0x3ac },
- { 0x388, 0x3ad },
- { 0x389, 0x3ae },
- { 0x38a, 0x3af },
- { 0x391, 0x3b1 },
- { 0x392, 0x3b2 },
- { 0x393, 0x3b3 },
- { 0x394, 0x3b4 },
- { 0x395, 0x3b5 },
- { 0x396, 0x3b6 },
- { 0x397, 0x3b7 },
- { 0x398, 0x3b8 },
- { 0x399, 0x3b9 },
- { 0x39a, 0x3ba },
- { 0x39b, 0x3bb },
- { 0x39c, 0x3bc },
- { 0x39d, 0x3bd },
- { 0x39e, 0x3be },
- { 0x39f, 0x3bf },
- { 0x3a0, 0x3c0 },
- { 0x3a1, 0x3c1 },
- { 0x3a3, 0x3c3 },
- { 0x3a4, 0x3c4 },
- { 0x3a5, 0x3c5 },
- { 0x3a6, 0x3c6 },
- { 0x3a7, 0x3c7 },
- { 0x3a8, 0x3c8 },
- { 0x3a9, 0x3c9 },
- { 0x3aa, 0x3ca },
- { 0x3ab, 0x3cb },
- { 0x38c, 0x3cc },
- { 0x38e, 0x3cd },
- { 0x38f, 0x3ce },
- { 0x3e2, 0x3e3 },
- { 0x3e4, 0x3e5 },
- { 0x3e6, 0x3e7 },
- { 0x3e8, 0x3e9 },
- { 0x3ea, 0x3eb },
- { 0x3ec, 0x3ed },
- { 0x3ee, 0x3ef },
- { 0x410, 0x430 },
- { 0x411, 0x431 },
- { 0x412, 0x432 },
- { 0x413, 0x433 },
- { 0x414, 0x434 },
- { 0x415, 0x435 },
- { 0x416, 0x436 },
- { 0x417, 0x437 },
- { 0x418, 0x438 },
- { 0x419, 0x439 },
- { 0x41a, 0x43a },
- { 0x41b, 0x43b },
- { 0x41c, 0x43c },
- { 0x41d, 0x43d },
- { 0x41e, 0x43e },
- { 0x41f, 0x43f },
- { 0x420, 0x440 },
- { 0x421, 0x441 },
- { 0x422, 0x442 },
- { 0x423, 0x443 },
- { 0x424, 0x444 },
- { 0x425, 0x445 },
- { 0x426, 0x446 },
- { 0x427, 0x447 },
- { 0x428, 0x448 },
- { 0x429, 0x449 },
- { 0x42a, 0x44a },
- { 0x42b, 0x44b },
- { 0x42c, 0x44c },
- { 0x42d, 0x44d },
- { 0x42e, 0x44e },
- { 0x42f, 0x44f },
- { 0x401, 0x451 },
- { 0x402, 0x452 },
- { 0x403, 0x453 },
- { 0x404, 0x454 },
- { 0x405, 0x455 },
- { 0x406, 0x456 },
- { 0x407, 0x457 },
- { 0x408, 0x458 },
- { 0x409, 0x459 },
- { 0x40a, 0x45a },
- { 0x40b, 0x45b },
- { 0x40c, 0x45c },
- { 0x40e, 0x45e },
- { 0x40f, 0x45f },
- { 0x460, 0x461 },
- { 0x462, 0x463 },
- { 0x464, 0x465 },
- { 0x466, 0x467 },
- { 0x468, 0x469 },
- { 0x46a, 0x46b },
- { 0x46c, 0x46d },
- { 0x46e, 0x46f },
- { 0x470, 0x471 },
- { 0x472, 0x473 },
- { 0x474, 0x475 },
- { 0x476, 0x477 },
- { 0x478, 0x479 },
- { 0x47a, 0x47b },
- { 0x47c, 0x47d },
- { 0x47e, 0x47f },
- { 0x480, 0x481 },
- { 0x490, 0x491 },
- { 0x492, 0x493 },
- { 0x494, 0x495 },
- { 0x496, 0x497 },
- { 0x498, 0x499 },
- { 0x49a, 0x49b },
- { 0x49c, 0x49d },
- { 0x49e, 0x49f },
- { 0x4a0, 0x4a1 },
- { 0x4a2, 0x4a3 },
- { 0x4a4, 0x4a5 },
- { 0x4a6, 0x4a7 },
- { 0x4a8, 0x4a9 },
- { 0x4aa, 0x4ab },
- { 0x4ac, 0x4ad },
- { 0x4ae, 0x4af },
- { 0x4b0, 0x4b1 },
- { 0x4b2, 0x4b3 },
- { 0x4b4, 0x4b5 },
- { 0x4b6, 0x4b7 },
- { 0x4b8, 0x4b9 },
- { 0x4ba, 0x4bb },
- { 0x4bc, 0x4bd },
- { 0x4be, 0x4bf },
- { 0x4c1, 0x4c2 },
- { 0x4c3, 0x4c4 },
- { 0x4c7, 0x4c8 },
- { 0x4cb, 0x4cc },
- { 0x4d0, 0x4d1 },
- { 0x4d2, 0x4d3 },
- { 0x4d4, 0x4d5 },
- { 0x4d6, 0x4d7 },
- { 0x4d8, 0x4d9 },
- { 0x4da, 0x4db },
- { 0x4dc, 0x4dd },
- { 0x4de, 0x4df },
- { 0x4e0, 0x4e1 },
- { 0x4e2, 0x4e3 },
- { 0x4e4, 0x4e5 },
- { 0x4e6, 0x4e7 },
- { 0x4e8, 0x4e9 },
- { 0x4ea, 0x4eb },
- { 0x4ee, 0x4ef },
- { 0x4f0, 0x4f1 },
- { 0x4f2, 0x4f3 },
- { 0x4f4, 0x4f5 },
- { 0x4f8, 0x4f9 },
- { 0x531, 0x561 },
- { 0x532, 0x562 },
- { 0x533, 0x563 },
- { 0x534, 0x564 },
- { 0x535, 0x565 },
- { 0x536, 0x566 },
- { 0x537, 0x567 },
- { 0x538, 0x568 },
- { 0x539, 0x569 },
- { 0x53a, 0x56a },
- { 0x53b, 0x56b },
- { 0x53c, 0x56c },
- { 0x53d, 0x56d },
- { 0x53e, 0x56e },
- { 0x53f, 0x56f },
- { 0x540, 0x570 },
- { 0x541, 0x571 },
- { 0x542, 0x572 },
- { 0x543, 0x573 },
- { 0x544, 0x574 },
- { 0x545, 0x575 },
- { 0x546, 0x576 },
- { 0x547, 0x577 },
- { 0x548, 0x578 },
- { 0x549, 0x579 },
- { 0x54a, 0x57a },
- { 0x54b, 0x57b },
- { 0x54c, 0x57c },
- { 0x54d, 0x57d },
- { 0x54e, 0x57e },
- { 0x54f, 0x57f },
- { 0x550, 0x580 },
- { 0x551, 0x581 },
- { 0x552, 0x582 },
- { 0x553, 0x583 },
- { 0x554, 0x584 },
- { 0x555, 0x585 },
- { 0x556, 0x586 },
- { 0x10a0, 0x10d0 },
- { 0x10a1, 0x10d1 },
- { 0x10a2, 0x10d2 },
- { 0x10a3, 0x10d3 },
- { 0x10a4, 0x10d4 },
- { 0x10a5, 0x10d5 },
- { 0x10a6, 0x10d6 },
- { 0x10a7, 0x10d7 },
- { 0x10a8, 0x10d8 },
- { 0x10a9, 0x10d9 },
- { 0x10aa, 0x10da },
- { 0x10ab, 0x10db },
- { 0x10ac, 0x10dc },
- { 0x10ad, 0x10dd },
- { 0x10ae, 0x10de },
- { 0x10af, 0x10df },
- { 0x10b0, 0x10e0 },
- { 0x10b1, 0x10e1 },
- { 0x10b2, 0x10e2 },
- { 0x10b3, 0x10e3 },
- { 0x10b4, 0x10e4 },
- { 0x10b5, 0x10e5 },
- { 0x10b6, 0x10e6 },
- { 0x10b7, 0x10e7 },
- { 0x10b8, 0x10e8 },
- { 0x10b9, 0x10e9 },
- { 0x10ba, 0x10ea },
- { 0x10bb, 0x10eb },
- { 0x10bc, 0x10ec },
- { 0x10bd, 0x10ed },
- { 0x10be, 0x10ee },
- { 0x10bf, 0x10ef },
- { 0x10c0, 0x10f0 },
- { 0x10c1, 0x10f1 },
- { 0x10c2, 0x10f2 },
- { 0x10c3, 0x10f3 },
- { 0x10c4, 0x10f4 },
- { 0x10c5, 0x10f5 },
- { 0x1e00, 0x1e01 },
- { 0x1e02, 0x1e03 },
- { 0x1e04, 0x1e05 },
- { 0x1e06, 0x1e07 },
- { 0x1e08, 0x1e09 },
- { 0x1e0a, 0x1e0b },
- { 0x1e0c, 0x1e0d },
- { 0x1e0e, 0x1e0f },
- { 0x1e10, 0x1e11 },
- { 0x1e12, 0x1e13 },
- { 0x1e14, 0x1e15 },
- { 0x1e16, 0x1e17 },
- { 0x1e18, 0x1e19 },
- { 0x1e1a, 0x1e1b },
- { 0x1e1c, 0x1e1d },
- { 0x1e1e, 0x1e1f },
- { 0x1e20, 0x1e21 },
- { 0x1e22, 0x1e23 },
- { 0x1e24, 0x1e25 },
- { 0x1e26, 0x1e27 },
- { 0x1e28, 0x1e29 },
- { 0x1e2a, 0x1e2b },
- { 0x1e2c, 0x1e2d },
- { 0x1e2e, 0x1e2f },
- { 0x1e30, 0x1e31 },
- { 0x1e32, 0x1e33 },
- { 0x1e34, 0x1e35 },
- { 0x1e36, 0x1e37 },
- { 0x1e38, 0x1e39 },
- { 0x1e3a, 0x1e3b },
- { 0x1e3c, 0x1e3d },
- { 0x1e3e, 0x1e3f },
- { 0x1e40, 0x1e41 },
- { 0x1e42, 0x1e43 },
- { 0x1e44, 0x1e45 },
- { 0x1e46, 0x1e47 },
- { 0x1e48, 0x1e49 },
- { 0x1e4a, 0x1e4b },
- { 0x1e4c, 0x1e4d },
- { 0x1e4e, 0x1e4f },
- { 0x1e50, 0x1e51 },
- { 0x1e52, 0x1e53 },
- { 0x1e54, 0x1e55 },
- { 0x1e56, 0x1e57 },
- { 0x1e58, 0x1e59 },
- { 0x1e5a, 0x1e5b },
- { 0x1e5c, 0x1e5d },
- { 0x1e5e, 0x1e5f },
- { 0x1e60, 0x1e61 },
- { 0x1e62, 0x1e63 },
- { 0x1e64, 0x1e65 },
- { 0x1e66, 0x1e67 },
- { 0x1e68, 0x1e69 },
- { 0x1e6a, 0x1e6b },
- { 0x1e6c, 0x1e6d },
- { 0x1e6e, 0x1e6f },
- { 0x1e70, 0x1e71 },
- { 0x1e72, 0x1e73 },
- { 0x1e74, 0x1e75 },
- { 0x1e76, 0x1e77 },
- { 0x1e78, 0x1e79 },
- { 0x1e7a, 0x1e7b },
- { 0x1e7c, 0x1e7d },
- { 0x1e7e, 0x1e7f },
- { 0x1e80, 0x1e81 },
- { 0x1e82, 0x1e83 },
- { 0x1e84, 0x1e85 },
- { 0x1e86, 0x1e87 },
- { 0x1e88, 0x1e89 },
- { 0x1e8a, 0x1e8b },
- { 0x1e8c, 0x1e8d },
- { 0x1e8e, 0x1e8f },
- { 0x1e90, 0x1e91 },
- { 0x1e92, 0x1e93 },
- { 0x1e94, 0x1e95 },
- { 0x1ea0, 0x1ea1 },
- { 0x1ea2, 0x1ea3 },
- { 0x1ea4, 0x1ea5 },
- { 0x1ea6, 0x1ea7 },
- { 0x1ea8, 0x1ea9 },
- { 0x1eaa, 0x1eab },
- { 0x1eac, 0x1ead },
- { 0x1eae, 0x1eaf },
- { 0x1eb0, 0x1eb1 },
- { 0x1eb2, 0x1eb3 },
- { 0x1eb4, 0x1eb5 },
- { 0x1eb6, 0x1eb7 },
- { 0x1eb8, 0x1eb9 },
- { 0x1eba, 0x1ebb },
- { 0x1ebc, 0x1ebd },
- { 0x1ebe, 0x1ebf },
- { 0x1ec0, 0x1ec1 },
- { 0x1ec2, 0x1ec3 },
- { 0x1ec4, 0x1ec5 },
- { 0x1ec6, 0x1ec7 },
- { 0x1ec8, 0x1ec9 },
- { 0x1eca, 0x1ecb },
- { 0x1ecc, 0x1ecd },
- { 0x1ece, 0x1ecf },
- { 0x1ed0, 0x1ed1 },
- { 0x1ed2, 0x1ed3 },
- { 0x1ed4, 0x1ed5 },
- { 0x1ed6, 0x1ed7 },
- { 0x1ed8, 0x1ed9 },
- { 0x1eda, 0x1edb },
- { 0x1edc, 0x1edd },
- { 0x1ede, 0x1edf },
- { 0x1ee0, 0x1ee1 },
- { 0x1ee2, 0x1ee3 },
- { 0x1ee4, 0x1ee5 },
- { 0x1ee6, 0x1ee7 },
- { 0x1ee8, 0x1ee9 },
- { 0x1eea, 0x1eeb },
- { 0x1eec, 0x1eed },
- { 0x1eee, 0x1eef },
- { 0x1ef0, 0x1ef1 },
- { 0x1ef2, 0x1ef3 },
- { 0x1ef4, 0x1ef5 },
- { 0x1ef6, 0x1ef7 },
- { 0x1ef8, 0x1ef9 },
- { 0x1f08, 0x1f00 },
- { 0x1f09, 0x1f01 },
- { 0x1f0a, 0x1f02 },
- { 0x1f0b, 0x1f03 },
- { 0x1f0c, 0x1f04 },
- { 0x1f0d, 0x1f05 },
- { 0x1f0e, 0x1f06 },
- { 0x1f0f, 0x1f07 },
- { 0x1f18, 0x1f10 },
- { 0x1f19, 0x1f11 },
- { 0x1f1a, 0x1f12 },
- { 0x1f1b, 0x1f13 },
- { 0x1f1c, 0x1f14 },
- { 0x1f1d, 0x1f15 },
- { 0x1f28, 0x1f20 },
- { 0x1f29, 0x1f21 },
- { 0x1f2a, 0x1f22 },
- { 0x1f2b, 0x1f23 },
- { 0x1f2c, 0x1f24 },
- { 0x1f2d, 0x1f25 },
- { 0x1f2e, 0x1f26 },
- { 0x1f2f, 0x1f27 },
- { 0x1f38, 0x1f30 },
- { 0x1f39, 0x1f31 },
- { 0x1f3a, 0x1f32 },
- { 0x1f3b, 0x1f33 },
- { 0x1f3c, 0x1f34 },
- { 0x1f3d, 0x1f35 },
- { 0x1f3e, 0x1f36 },
- { 0x1f3f, 0x1f37 },
- { 0x1f48, 0x1f40 },
- { 0x1f49, 0x1f41 },
- { 0x1f4a, 0x1f42 },
- { 0x1f4b, 0x1f43 },
- { 0x1f4c, 0x1f44 },
- { 0x1f4d, 0x1f45 },
- { 0x1f59, 0x1f51 },
- { 0x1f5b, 0x1f53 },
- { 0x1f5d, 0x1f55 },
- { 0x1f5f, 0x1f57 },
- { 0x1f68, 0x1f60 },
- { 0x1f69, 0x1f61 },
- { 0x1f6a, 0x1f62 },
- { 0x1f6b, 0x1f63 },
- { 0x1f6c, 0x1f64 },
- { 0x1f6d, 0x1f65 },
- { 0x1f6e, 0x1f66 },
- { 0x1f6f, 0x1f67 },
- { 0x1f88, 0x1f80 },
- { 0x1f89, 0x1f81 },
- { 0x1f8a, 0x1f82 },
- { 0x1f8b, 0x1f83 },
- { 0x1f8c, 0x1f84 },
- { 0x1f8d, 0x1f85 },
- { 0x1f8e, 0x1f86 },
- { 0x1f8f, 0x1f87 },
- { 0x1f98, 0x1f90 },
- { 0x1f99, 0x1f91 },
- { 0x1f9a, 0x1f92 },
- { 0x1f9b, 0x1f93 },
- { 0x1f9c, 0x1f94 },
- { 0x1f9d, 0x1f95 },
- { 0x1f9e, 0x1f96 },
- { 0x1f9f, 0x1f97 },
- { 0x1fa8, 0x1fa0 },
- { 0x1fa9, 0x1fa1 },
- { 0x1faa, 0x1fa2 },
- { 0x1fab, 0x1fa3 },
- { 0x1fac, 0x1fa4 },
- { 0x1fad, 0x1fa5 },
- { 0x1fae, 0x1fa6 },
- { 0x1faf, 0x1fa7 },
- { 0x1fb8, 0x1fb0 },
- { 0x1fb9, 0x1fb1 },
- { 0x1fd8, 0x1fd0 },
- { 0x1fd9, 0x1fd1 },
- { 0x1fe8, 0x1fe0 },
- { 0x1fe9, 0x1fe1 },
- { 0x24b6, 0x24d0 },
- { 0x24b7, 0x24d1 },
- { 0x24b8, 0x24d2 },
- { 0x24b9, 0x24d3 },
- { 0x24ba, 0x24d4 },
- { 0x24bb, 0x24d5 },
- { 0x24bc, 0x24d6 },
- { 0x24bd, 0x24d7 },
- { 0x24be, 0x24d8 },
- { 0x24bf, 0x24d9 },
- { 0x24c0, 0x24da },
- { 0x24c1, 0x24db },
- { 0x24c2, 0x24dc },
- { 0x24c3, 0x24dd },
- { 0x24c4, 0x24de },
- { 0x24c5, 0x24df },
- { 0x24c6, 0x24e0 },
- { 0x24c7, 0x24e1 },
- { 0x24c8, 0x24e2 },
- { 0x24c9, 0x24e3 },
- { 0x24ca, 0x24e4 },
- { 0x24cb, 0x24e5 },
- { 0x24cc, 0x24e6 },
- { 0x24cd, 0x24e7 },
- { 0x24ce, 0x24e8 },
- { 0x24cf, 0x24e9 },
- { 0xff21, 0xff41 },
- { 0xff22, 0xff42 },
- { 0xff23, 0xff43 },
- { 0xff24, 0xff44 },
- { 0xff25, 0xff45 },
- { 0xff26, 0xff46 },
- { 0xff27, 0xff47 },
- { 0xff28, 0xff48 },
- { 0xff29, 0xff49 },
- { 0xff2a, 0xff4a },
- { 0xff2b, 0xff4b },
- { 0xff2c, 0xff4c },
- { 0xff2d, 0xff4d },
- { 0xff2e, 0xff4e },
- { 0xff2f, 0xff4f },
- { 0xff30, 0xff50 },
- { 0xff31, 0xff51 },
- { 0xff32, 0xff52 },
- { 0xff33, 0xff53 },
- { 0xff34, 0xff54 },
- { 0xff35, 0xff55 },
- { 0xff36, 0xff56 },
- { 0xff37, 0xff57 },
- { 0xff38, 0xff58 },
- { 0xff39, 0xff59 },
- { 0xff3a, 0xff5a }
+ { 0x0041, 0x0061 },
+ { 0x0042, 0x0062 },
+ { 0x0043, 0x0063 },
+ { 0x0044, 0x0064 },
+ { 0x0045, 0x0065 },
+ { 0x0046, 0x0066 },
+ { 0x0047, 0x0067 },
+ { 0x0048, 0x0068 },
+ { 0x0049, 0x0069 },
+ // { 0x0049, 0x0131 }, // dotless I
+ { 0x004A, 0x006A },
+ { 0x004B, 0x006B },
+ { 0x004C, 0x006C },
+ { 0x004D, 0x006D },
+ { 0x004E, 0x006E },
+ { 0x004F, 0x006F },
+ { 0x0050, 0x0070 },
+ { 0x0051, 0x0071 },
+ { 0x0052, 0x0072 },
+ { 0x0053, 0x0073 },
+ { 0x0054, 0x0074 },
+ { 0x0055, 0x0075 },
+ { 0x0056, 0x0076 },
+ { 0x0057, 0x0077 },
+ { 0x0058, 0x0078 },
+ { 0x0059, 0x0079 },
+ { 0x005A, 0x007A },
+ { 0x00C0, 0x00E0 },
+ { 0x00C1, 0x00E1 },
+ { 0x00C2, 0x00E2 },
+ { 0x00C3, 0x00E3 },
+ { 0x00C4, 0x00E4 },
+ { 0x00C5, 0x00E5 },
+ { 0x00C6, 0x00E6 },
+ { 0x00C7, 0x00E7 },
+ { 0x00C8, 0x00E8 },
+ { 0x00C9, 0x00E9 },
+ { 0x00CA, 0x00EA },
+ { 0x00CB, 0x00EB },
+ { 0x00CC, 0x00EC },
+ { 0x00CD, 0x00ED },
+ { 0x00CE, 0x00EE },
+ { 0x00CF, 0x00EF },
+ { 0x00D0, 0x00F0 },
+ { 0x00D1, 0x00F1 },
+ { 0x00D2, 0x00F2 },
+ { 0x00D3, 0x00F3 },
+ { 0x00D4, 0x00F4 },
+ { 0x00D5, 0x00F5 },
+ { 0x00D6, 0x00F6 },
+ { 0x00D8, 0x00F8 },
+ { 0x00D9, 0x00F9 },
+ { 0x00DA, 0x00FA },
+ { 0x00DB, 0x00FB },
+ { 0x00DC, 0x00FC },
+ { 0x00DD, 0x00FD },
+ { 0x00DE, 0x00FE },
+ { 0x0100, 0x0101 },
+ { 0x0102, 0x0103 },
+ { 0x0104, 0x0105 },
+ { 0x0106, 0x0107 },
+ { 0x0108, 0x0109 },
+ { 0x010A, 0x010B },
+ { 0x010C, 0x010D },
+ { 0x010E, 0x010F },
+ { 0x0110, 0x0111 },
+ { 0x0112, 0x0113 },
+ { 0x0114, 0x0115 },
+ { 0x0116, 0x0117 },
+ { 0x0118, 0x0119 },
+ { 0x011A, 0x011B },
+ { 0x011C, 0x011D },
+ { 0x011E, 0x011F },
+ { 0x0120, 0x0121 },
+ { 0x0122, 0x0123 },
+ { 0x0124, 0x0125 },
+ { 0x0126, 0x0127 },
+ { 0x0128, 0x0129 },
+ { 0x012A, 0x012B },
+ { 0x012C, 0x012D },
+ { 0x012E, 0x012F },
+ { 0x0132, 0x0133 },
+ { 0x0134, 0x0135 },
+ { 0x0136, 0x0137 },
+ { 0x0139, 0x013A },
+ { 0x013B, 0x013C },
+ { 0x013D, 0x013E },
+ { 0x013F, 0x0140 },
+ { 0x0141, 0x0142 },
+ { 0x0143, 0x0144 },
+ { 0x0145, 0x0146 },
+ { 0x0147, 0x0148 },
+ { 0x014A, 0x014B },
+ { 0x014C, 0x014D },
+ { 0x014E, 0x014F },
+ { 0x0150, 0x0151 },
+ { 0x0152, 0x0153 },
+ { 0x0154, 0x0155 },
+ { 0x0156, 0x0157 },
+ { 0x0158, 0x0159 },
+ { 0x015A, 0x015B },
+ { 0x015C, 0x015D },
+ { 0x015E, 0x015F },
+ { 0x0160, 0x0161 },
+ { 0x0162, 0x0163 },
+ { 0x0164, 0x0165 },
+ { 0x0166, 0x0167 },
+ { 0x0168, 0x0169 },
+ { 0x016A, 0x016B },
+ { 0x016C, 0x016D },
+ { 0x016E, 0x016F },
+ { 0x0170, 0x0171 },
+ { 0x0172, 0x0173 },
+ { 0x0174, 0x0175 },
+ { 0x0176, 0x0177 },
+ { 0x0178, 0x00FF },
+ { 0x0179, 0x017A },
+ { 0x017B, 0x017C },
+ { 0x017D, 0x017E },
+ { 0x0181, 0x0253 },
+ { 0x0182, 0x0183 },
+ { 0x0184, 0x0185 },
+ { 0x0186, 0x0254 },
+ { 0x0187, 0x0188 },
+ { 0x018A, 0x0257 },
+ { 0x018B, 0x018C },
+ { 0x018E, 0x0258 },
+ { 0x018F, 0x0259 },
+ { 0x0190, 0x025B },
+ { 0x0191, 0x0192 },
+ { 0x0193, 0x0260 },
+ { 0x0194, 0x0263 },
+ { 0x0196, 0x0269 },
+ { 0x0197, 0x0268 },
+ { 0x0198, 0x0199 },
+ { 0x019C, 0x026F },
+ { 0x019D, 0x0272 },
+ { 0x019F, 0x0275 },
+ { 0x01A0, 0x01A1 },
+ { 0x01A2, 0x01A3 },
+ { 0x01A4, 0x01A5 },
+ { 0x01A7, 0x01A8 },
+ { 0x01A9, 0x0283 },
+ { 0x01AC, 0x01AD },
+ { 0x01AE, 0x0288 },
+ { 0x01AF, 0x01B0 },
+ { 0x01B1, 0x028A },
+ { 0x01B2, 0x028B },
+ { 0x01B3, 0x01B4 },
+ { 0x01B5, 0x01B6 },
+ { 0x01B7, 0x0292 },
+ { 0x01B8, 0x01B9 },
+ { 0x01BC, 0x01BD },
+ { 0x01C4, 0x01C6 },
+ { 0x01C7, 0x01C9 },
+ { 0x01CA, 0x01CC },
+ { 0x01CD, 0x01CE },
+ { 0x01CF, 0x01D0 },
+ { 0x01D1, 0x01D2 },
+ { 0x01D3, 0x01D4 },
+ { 0x01D5, 0x01D6 },
+ { 0x01D7, 0x01D8 },
+ { 0x01D9, 0x01DA },
+ { 0x01DB, 0x01DC },
+ { 0x01DE, 0x01DF },
+ { 0x01E0, 0x01E1 },
+ { 0x01E2, 0x01E3 },
+ { 0x01E4, 0x01E5 },
+ { 0x01E6, 0x01E7 },
+ { 0x01E8, 0x01E9 },
+ { 0x01EA, 0x01EB },
+ { 0x01EC, 0x01ED },
+ { 0x01EE, 0x01EF },
+ { 0x01F1, 0x01F3 },
+ { 0x01F4, 0x01F5 },
+ { 0x01FA, 0x01FB },
+ { 0x01FC, 0x01FD },
+ { 0x01FE, 0x01FF },
+ { 0x0200, 0x0201 },
+ { 0x0202, 0x0203 },
+ { 0x0204, 0x0205 },
+ { 0x0206, 0x0207 },
+ { 0x0208, 0x0209 },
+ { 0x020A, 0x020B },
+ { 0x020C, 0x020D },
+ { 0x020E, 0x020F },
+ { 0x0210, 0x0211 },
+ { 0x0212, 0x0213 },
+ { 0x0214, 0x0215 },
+ { 0x0216, 0x0217 },
+ { 0x0386, 0x03AC },
+ { 0x0388, 0x03AD },
+ { 0x0389, 0x03AE },
+ { 0x038A, 0x03AF },
+ { 0x038C, 0x03CC },
+ { 0x038E, 0x03CD },
+ { 0x038F, 0x03CE },
+ { 0x0391, 0x03B1 },
+ { 0x0392, 0x03B2 },
+ { 0x0393, 0x03B3 },
+ { 0x0394, 0x03B4 },
+ { 0x0395, 0x03B5 },
+ { 0x0396, 0x03B6 },
+ { 0x0397, 0x03B7 },
+ { 0x0398, 0x03B8 },
+ { 0x0399, 0x03B9 },
+ { 0x039A, 0x03BA },
+ { 0x039B, 0x03BB },
+ { 0x039C, 0x03BC },
+ { 0x039D, 0x03BD },
+ { 0x039E, 0x03BE },
+ { 0x039F, 0x03BF },
+ { 0x03A0, 0x03C0 },
+ { 0x03A1, 0x03C1 },
+ { 0x03A3, 0x03C3 },
+ { 0x03A4, 0x03C4 },
+ { 0x03A5, 0x03C5 },
+ { 0x03A6, 0x03C6 },
+ { 0x03A7, 0x03C7 },
+ { 0x03A8, 0x03C8 },
+ { 0x03A9, 0x03C9 },
+ { 0x03AA, 0x03CA },
+ { 0x03AB, 0x03CB },
+ { 0x03E2, 0x03E3 },
+ { 0x03E4, 0x03E5 },
+ { 0x03E6, 0x03E7 },
+ { 0x03E8, 0x03E9 },
+ { 0x03EA, 0x03EB },
+ { 0x03EC, 0x03ED },
+ { 0x03EE, 0x03EF },
+ { 0x0401, 0x0451 },
+ { 0x0402, 0x0452 },
+ { 0x0403, 0x0453 },
+ { 0x0404, 0x0454 },
+ { 0x0405, 0x0455 },
+ { 0x0406, 0x0456 },
+ { 0x0407, 0x0457 },
+ { 0x0408, 0x0458 },
+ { 0x0409, 0x0459 },
+ { 0x040A, 0x045A },
+ { 0x040B, 0x045B },
+ { 0x040C, 0x045C },
+ { 0x040E, 0x045E },
+ { 0x040F, 0x045F },
+ { 0x0410, 0x0430 },
+ { 0x0411, 0x0431 },
+ { 0x0412, 0x0432 },
+ { 0x0413, 0x0433 },
+ { 0x0414, 0x0434 },
+ { 0x0415, 0x0435 },
+ { 0x0416, 0x0436 },
+ { 0x0417, 0x0437 },
+ { 0x0418, 0x0438 },
+ { 0x0419, 0x0439 },
+ { 0x041A, 0x043A },
+ { 0x041B, 0x043B },
+ { 0x041C, 0x043C },
+ { 0x041D, 0x043D },
+ { 0x041E, 0x043E },
+ { 0x041F, 0x043F },
+ { 0x0420, 0x0440 },
+ { 0x0421, 0x0441 },
+ { 0x0422, 0x0442 },
+ { 0x0423, 0x0443 },
+ { 0x0424, 0x0444 },
+ { 0x0425, 0x0445 },
+ { 0x0426, 0x0446 },
+ { 0x0427, 0x0447 },
+ { 0x0428, 0x0448 },
+ { 0x0429, 0x0449 },
+ { 0x042A, 0x044A },
+ { 0x042B, 0x044B },
+ { 0x042C, 0x044C },
+ { 0x042D, 0x044D },
+ { 0x042E, 0x044E },
+ { 0x042F, 0x044F },
+ { 0x0460, 0x0461 },
+ { 0x0462, 0x0463 },
+ { 0x0464, 0x0465 },
+ { 0x0466, 0x0467 },
+ { 0x0468, 0x0469 },
+ { 0x046A, 0x046B },
+ { 0x046C, 0x046D },
+ { 0x046E, 0x046F },
+ { 0x0470, 0x0471 },
+ { 0x0472, 0x0473 },
+ { 0x0474, 0x0475 },
+ { 0x0476, 0x0477 },
+ { 0x0478, 0x0479 },
+ { 0x047A, 0x047B },
+ { 0x047C, 0x047D },
+ { 0x047E, 0x047F },
+ { 0x0480, 0x0481 },
+ { 0x0490, 0x0491 },
+ { 0x0492, 0x0493 },
+ { 0x0494, 0x0495 },
+ { 0x0496, 0x0497 },
+ { 0x0498, 0x0499 },
+ { 0x049A, 0x049B },
+ { 0x049C, 0x049D },
+ { 0x049E, 0x049F },
+ { 0x04A0, 0x04A1 },
+ { 0x04A2, 0x04A3 },
+ { 0x04A4, 0x04A5 },
+ { 0x04A6, 0x04A7 },
+ { 0x04A8, 0x04A9 },
+ { 0x04AA, 0x04AB },
+ { 0x04AC, 0x04AD },
+ { 0x04AE, 0x04AF },
+ { 0x04B0, 0x04B1 },
+ { 0x04B2, 0x04B3 },
+ { 0x04B4, 0x04B5 },
+ { 0x04B6, 0x04B7 },
+ { 0x04B8, 0x04B9 },
+ { 0x04BA, 0x04BB },
+ { 0x04BC, 0x04BD },
+ { 0x04BE, 0x04BF },
+ { 0x04C1, 0x04C2 },
+ { 0x04C3, 0x04C4 },
+ { 0x04C7, 0x04C8 },
+ { 0x04CB, 0x04CC },
+ { 0x04D0, 0x04D1 },
+ { 0x04D2, 0x04D3 },
+ { 0x04D4, 0x04D5 },
+ { 0x04D6, 0x04D7 },
+ { 0x04D8, 0x04D9 },
+ { 0x04DA, 0x04DB },
+ { 0x04DC, 0x04DD },
+ { 0x04DE, 0x04DF },
+ { 0x04E0, 0x04E1 },
+ { 0x04E2, 0x04E3 },
+ { 0x04E4, 0x04E5 },
+ { 0x04E6, 0x04E7 },
+ { 0x04E8, 0x04E9 },
+ { 0x04EA, 0x04EB },
+ { 0x04EE, 0x04EF },
+ { 0x04F0, 0x04F1 },
+ { 0x04F2, 0x04F3 },
+ { 0x04F4, 0x04F5 },
+ { 0x04F8, 0x04F9 },
+ { 0x0531, 0x0561 },
+ { 0x0532, 0x0562 },
+ { 0x0533, 0x0563 },
+ { 0x0534, 0x0564 },
+ { 0x0535, 0x0565 },
+ { 0x0536, 0x0566 },
+ { 0x0537, 0x0567 },
+ { 0x0538, 0x0568 },
+ { 0x0539, 0x0569 },
+ { 0x053A, 0x056A },
+ { 0x053B, 0x056B },
+ { 0x053C, 0x056C },
+ { 0x053D, 0x056D },
+ { 0x053E, 0x056E },
+ { 0x053F, 0x056F },
+ { 0x0540, 0x0570 },
+ { 0x0541, 0x0571 },
+ { 0x0542, 0x0572 },
+ { 0x0543, 0x0573 },
+ { 0x0544, 0x0574 },
+ { 0x0545, 0x0575 },
+ { 0x0546, 0x0576 },
+ { 0x0547, 0x0577 },
+ { 0x0548, 0x0578 },
+ { 0x0549, 0x0579 },
+ { 0x054A, 0x057A },
+ { 0x054B, 0x057B },
+ { 0x054C, 0x057C },
+ { 0x054D, 0x057D },
+ { 0x054E, 0x057E },
+ { 0x054F, 0x057F },
+ { 0x0550, 0x0580 },
+ { 0x0551, 0x0581 },
+ { 0x0552, 0x0582 },
+ { 0x0553, 0x0583 },
+ { 0x0554, 0x0584 },
+ { 0x0555, 0x0585 },
+ { 0x0556, 0x0586 },
+ { 0x10A0, 0x10D0 },
+ { 0x10A1, 0x10D1 },
+ { 0x10A2, 0x10D2 },
+ { 0x10A3, 0x10D3 },
+ { 0x10A4, 0x10D4 },
+ { 0x10A5, 0x10D5 },
+ { 0x10A6, 0x10D6 },
+ { 0x10A7, 0x10D7 },
+ { 0x10A8, 0x10D8 },
+ { 0x10A9, 0x10D9 },
+ { 0x10AA, 0x10DA },
+ { 0x10AB, 0x10DB },
+ { 0x10AC, 0x10DC },
+ { 0x10AD, 0x10DD },
+ { 0x10AE, 0x10DE },
+ { 0x10AF, 0x10DF },
+ { 0x10B0, 0x10E0 },
+ { 0x10B1, 0x10E1 },
+ { 0x10B2, 0x10E2 },
+ { 0x10B3, 0x10E3 },
+ { 0x10B4, 0x10E4 },
+ { 0x10B5, 0x10E5 },
+ { 0x10B6, 0x10E6 },
+ { 0x10B7, 0x10E7 },
+ { 0x10B8, 0x10E8 },
+ { 0x10B9, 0x10E9 },
+ { 0x10BA, 0x10EA },
+ { 0x10BB, 0x10EB },
+ { 0x10BC, 0x10EC },
+ { 0x10BD, 0x10ED },
+ { 0x10BE, 0x10EE },
+ { 0x10BF, 0x10EF },
+ { 0x10C0, 0x10F0 },
+ { 0x10C1, 0x10F1 },
+ { 0x10C2, 0x10F2 },
+ { 0x10C3, 0x10F3 },
+ { 0x10C4, 0x10F4 },
+ { 0x10C5, 0x10F5 },
+ { 0x1E00, 0x1E01 },
+ { 0x1E02, 0x1E03 },
+ { 0x1E04, 0x1E05 },
+ { 0x1E06, 0x1E07 },
+ { 0x1E08, 0x1E09 },
+ { 0x1E0A, 0x1E0B },
+ { 0x1E0C, 0x1E0D },
+ { 0x1E0E, 0x1E0F },
+ { 0x1E10, 0x1E11 },
+ { 0x1E12, 0x1E13 },
+ { 0x1E14, 0x1E15 },
+ { 0x1E16, 0x1E17 },
+ { 0x1E18, 0x1E19 },
+ { 0x1E1A, 0x1E1B },
+ { 0x1E1C, 0x1E1D },
+ { 0x1E1E, 0x1E1F },
+ { 0x1E20, 0x1E21 },
+ { 0x1E22, 0x1E23 },
+ { 0x1E24, 0x1E25 },
+ { 0x1E26, 0x1E27 },
+ { 0x1E28, 0x1E29 },
+ { 0x1E2A, 0x1E2B },
+ { 0x1E2C, 0x1E2D },
+ { 0x1E2E, 0x1E2F },
+ { 0x1E30, 0x1E31 },
+ { 0x1E32, 0x1E33 },
+ { 0x1E34, 0x1E35 },
+ { 0x1E36, 0x1E37 },
+ { 0x1E38, 0x1E39 },
+ { 0x1E3A, 0x1E3B },
+ { 0x1E3C, 0x1E3D },
+ { 0x1E3E, 0x1E3F },
+ { 0x1E40, 0x1E41 },
+ { 0x1E42, 0x1E43 },
+ { 0x1E44, 0x1E45 },
+ { 0x1E46, 0x1E47 },
+ { 0x1E48, 0x1E49 },
+ { 0x1E4A, 0x1E4B },
+ { 0x1E4C, 0x1E4D },
+ { 0x1E4E, 0x1E4F },
+ { 0x1E50, 0x1E51 },
+ { 0x1E52, 0x1E53 },
+ { 0x1E54, 0x1E55 },
+ { 0x1E56, 0x1E57 },
+ { 0x1E58, 0x1E59 },
+ { 0x1E5A, 0x1E5B },
+ { 0x1E5C, 0x1E5D },
+ { 0x1E5E, 0x1E5F },
+ { 0x1E60, 0x1E61 },
+ { 0x1E62, 0x1E63 },
+ { 0x1E64, 0x1E65 },
+ { 0x1E66, 0x1E67 },
+ { 0x1E68, 0x1E69 },
+ { 0x1E6A, 0x1E6B },
+ { 0x1E6C, 0x1E6D },
+ { 0x1E6E, 0x1E6F },
+ { 0x1E70, 0x1E71 },
+ { 0x1E72, 0x1E73 },
+ { 0x1E74, 0x1E75 },
+ { 0x1E76, 0x1E77 },
+ { 0x1E78, 0x1E79 },
+ { 0x1E7A, 0x1E7B },
+ { 0x1E7C, 0x1E7D },
+ { 0x1E7E, 0x1E7F },
+ { 0x1E80, 0x1E81 },
+ { 0x1E82, 0x1E83 },
+ { 0x1E84, 0x1E85 },
+ { 0x1E86, 0x1E87 },
+ { 0x1E88, 0x1E89 },
+ { 0x1E8A, 0x1E8B },
+ { 0x1E8C, 0x1E8D },
+ { 0x1E8E, 0x1E8F },
+ { 0x1E90, 0x1E91 },
+ { 0x1E92, 0x1E93 },
+ { 0x1E94, 0x1E95 },
+ { 0x1EA0, 0x1EA1 },
+ { 0x1EA2, 0x1EA3 },
+ { 0x1EA4, 0x1EA5 },
+ { 0x1EA6, 0x1EA7 },
+ { 0x1EA8, 0x1EA9 },
+ { 0x1EAA, 0x1EAB },
+ { 0x1EAC, 0x1EAD },
+ { 0x1EAE, 0x1EAF },
+ { 0x1EB0, 0x1EB1 },
+ { 0x1EB2, 0x1EB3 },
+ { 0x1EB4, 0x1EB5 },
+ { 0x1EB6, 0x1EB7 },
+ { 0x1EB8, 0x1EB9 },
+ { 0x1EBA, 0x1EBB },
+ { 0x1EBC, 0x1EBD },
+ { 0x1EBE, 0x1EBF },
+ { 0x1EC0, 0x1EC1 },
+ { 0x1EC2, 0x1EC3 },
+ { 0x1EC4, 0x1EC5 },
+ { 0x1EC6, 0x1EC7 },
+ { 0x1EC8, 0x1EC9 },
+ { 0x1ECA, 0x1ECB },
+ { 0x1ECC, 0x1ECD },
+ { 0x1ECE, 0x1ECF },
+ { 0x1ED0, 0x1ED1 },
+ { 0x1ED2, 0x1ED3 },
+ { 0x1ED4, 0x1ED5 },
+ { 0x1ED6, 0x1ED7 },
+ { 0x1ED8, 0x1ED9 },
+ { 0x1EDA, 0x1EDB },
+ { 0x1EDC, 0x1EDD },
+ { 0x1EDE, 0x1EDF },
+ { 0x1EE0, 0x1EE1 },
+ { 0x1EE2, 0x1EE3 },
+ { 0x1EE4, 0x1EE5 },
+ { 0x1EE6, 0x1EE7 },
+ { 0x1EE8, 0x1EE9 },
+ { 0x1EEA, 0x1EEB },
+ { 0x1EEC, 0x1EED },
+ { 0x1EEE, 0x1EEF },
+ { 0x1EF0, 0x1EF1 },
+ { 0x1EF2, 0x1EF3 },
+ { 0x1EF4, 0x1EF5 },
+ { 0x1EF6, 0x1EF7 },
+ { 0x1EF8, 0x1EF9 },
+ { 0x1F08, 0x1F00 },
+ { 0x1F09, 0x1F01 },
+ { 0x1F0A, 0x1F02 },
+ { 0x1F0B, 0x1F03 },
+ { 0x1F0C, 0x1F04 },
+ { 0x1F0D, 0x1F05 },
+ { 0x1F0E, 0x1F06 },
+ { 0x1F0F, 0x1F07 },
+ { 0x1F18, 0x1F10 },
+ { 0x1F19, 0x1F11 },
+ { 0x1F1A, 0x1F12 },
+ { 0x1F1B, 0x1F13 },
+ { 0x1F1C, 0x1F14 },
+ { 0x1F1D, 0x1F15 },
+ { 0x1F28, 0x1F20 },
+ { 0x1F29, 0x1F21 },
+ { 0x1F2A, 0x1F22 },
+ { 0x1F2B, 0x1F23 },
+ { 0x1F2C, 0x1F24 },
+ { 0x1F2D, 0x1F25 },
+ { 0x1F2E, 0x1F26 },
+ { 0x1F2F, 0x1F27 },
+ { 0x1F38, 0x1F30 },
+ { 0x1F39, 0x1F31 },
+ { 0x1F3A, 0x1F32 },
+ { 0x1F3B, 0x1F33 },
+ { 0x1F3C, 0x1F34 },
+ { 0x1F3D, 0x1F35 },
+ { 0x1F3E, 0x1F36 },
+ { 0x1F3F, 0x1F37 },
+ { 0x1F48, 0x1F40 },
+ { 0x1F49, 0x1F41 },
+ { 0x1F4A, 0x1F42 },
+ { 0x1F4B, 0x1F43 },
+ { 0x1F4C, 0x1F44 },
+ { 0x1F4D, 0x1F45 },
+ { 0x1F59, 0x1F51 },
+ { 0x1F5B, 0x1F53 },
+ { 0x1F5D, 0x1F55 },
+ { 0x1F5F, 0x1F57 },
+ { 0x1F68, 0x1F60 },
+ { 0x1F69, 0x1F61 },
+ { 0x1F6A, 0x1F62 },
+ { 0x1F6B, 0x1F63 },
+ { 0x1F6C, 0x1F64 },
+ { 0x1F6D, 0x1F65 },
+ { 0x1F6E, 0x1F66 },
+ { 0x1F6F, 0x1F67 },
+ { 0x1F88, 0x1F80 },
+ { 0x1F89, 0x1F81 },
+ { 0x1F8A, 0x1F82 },
+ { 0x1F8B, 0x1F83 },
+ { 0x1F8C, 0x1F84 },
+ { 0x1F8D, 0x1F85 },
+ { 0x1F8E, 0x1F86 },
+ { 0x1F8F, 0x1F87 },
+ { 0x1F98, 0x1F90 },
+ { 0x1F99, 0x1F91 },
+ { 0x1F9A, 0x1F92 },
+ { 0x1F9B, 0x1F93 },
+ { 0x1F9C, 0x1F94 },
+ { 0x1F9D, 0x1F95 },
+ { 0x1F9E, 0x1F96 },
+ { 0x1F9F, 0x1F97 },
+ { 0x1FA8, 0x1FA0 },
+ { 0x1FA9, 0x1FA1 },
+ { 0x1FAA, 0x1FA2 },
+ { 0x1FAB, 0x1FA3 },
+ { 0x1FAC, 0x1FA4 },
+ { 0x1FAD, 0x1FA5 },
+ { 0x1FAE, 0x1FA6 },
+ { 0x1FAF, 0x1FA7 },
+ { 0x1FB8, 0x1FB0 },
+ { 0x1FB9, 0x1FB1 },
+ { 0x1FD8, 0x1FD0 },
+ { 0x1FD9, 0x1FD1 },
+ { 0x1FE8, 0x1FE0 },
+ { 0x1FE9, 0x1FE1 },
+ { 0x24B6, 0x24D0 },
+ { 0x24B7, 0x24D1 },
+ { 0x24B8, 0x24D2 },
+ { 0x24B9, 0x24D3 },
+ { 0x24BA, 0x24D4 },
+ { 0x24BB, 0x24D5 },
+ { 0x24BC, 0x24D6 },
+ { 0x24BD, 0x24D7 },
+ { 0x24BE, 0x24D8 },
+ { 0x24BF, 0x24D9 },
+ { 0x24C0, 0x24DA },
+ { 0x24C1, 0x24DB },
+ { 0x24C2, 0x24DC },
+ { 0x24C3, 0x24DD },
+ { 0x24C4, 0x24DE },
+ { 0x24C5, 0x24DF },
+ { 0x24C6, 0x24E0 },
+ { 0x24C7, 0x24E1 },
+ { 0x24C8, 0x24E2 },
+ { 0x24C9, 0x24E3 },
+ { 0x24CA, 0x24E4 },
+ { 0x24CB, 0x24E5 },
+ { 0x24CC, 0x24E6 },
+ { 0x24CD, 0x24E7 },
+ { 0x24CE, 0x24E8 },
+ { 0x24CF, 0x24E9 },
+ { 0xFF21, 0xFF41 },
+ { 0xFF22, 0xFF42 },
+ { 0xFF23, 0xFF43 },
+ { 0xFF24, 0xFF44 },
+ { 0xFF25, 0xFF45 },
+ { 0xFF26, 0xFF46 },
+ { 0xFF27, 0xFF47 },
+ { 0xFF28, 0xFF48 },
+ { 0xFF29, 0xFF49 },
+ { 0xFF2A, 0xFF4A },
+ { 0xFF2B, 0xFF4B },
+ { 0xFF2C, 0xFF4C },
+ { 0xFF2D, 0xFF4D },
+ { 0xFF2E, 0xFF4E },
+ { 0xFF2F, 0xFF4F },
+ { 0xFF30, 0xFF50 },
+ { 0xFF31, 0xFF51 },
+ { 0xFF32, 0xFF52 },
+ { 0xFF33, 0xFF53 },
+ { 0xFF34, 0xFF54 },
+ { 0xFF35, 0xFF55 },
+ { 0xFF36, 0xFF56 },
+ { 0xFF37, 0xFF57 },
+ { 0xFF38, 0xFF58 },
+ { 0xFF39, 0xFF59 },
+ { 0xFF3A, 0xFF5A },
};
static int _find_upper(int ch) {
diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp
index e13164d50f..f7ca6d3bde 100644
--- a/core/undo_redo.cpp
+++ b/core/undo_redo.cpp
@@ -90,7 +90,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
actions.write[actions.size() - 1].last_tick = ticks;
merge_mode = p_mode;
-
+ merging = true;
} else {
Action new_action;
@@ -239,8 +239,8 @@ void UndoRedo::_pop_history_tail() {
}
}
-bool UndoRedo::is_commiting_action() const {
- return commiting > 0;
+bool UndoRedo::is_committing_action() const {
+ return committing > 0;
}
void UndoRedo::commit_action() {
@@ -250,9 +250,14 @@ void UndoRedo::commit_action() {
if (action_level > 0)
return; //still nested
- commiting++;
+ if (merging) {
+ version--;
+ merging = false;
+ }
+
+ committing++;
redo(); // perform action
- commiting--;
+ committing--;
if (callback && actions.size() > 0) {
callback(callback_ud, actions[actions.size() - 1].name);
}
@@ -391,11 +396,12 @@ void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_ca
UndoRedo::UndoRedo() {
- commiting = 0;
+ committing = 0;
version = 1;
action_level = 0;
current_action = -1;
merge_mode = MERGE_DISABLE;
+ merging = false;
callback = NULL;
callback_ud = NULL;
@@ -490,10 +496,8 @@ void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
ClassDB::bind_method(D_METHOD("commit_action"), &UndoRedo::commit_action);
- ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_commiting_action);
-
- //ClassDB::bind_method(D_METHOD("add_do_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_do_method);
- //ClassDB::bind_method(D_METHOD("add_undo_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_undo_method);
+ // FIXME: Typo in "commiting", fix in 4.0 when breaking compat.
+ ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_committing_action);
{
MethodInfo mi;
diff --git a/core/undo_redo.h b/core/undo_redo.h
index b626149ce6..e2cc6c659b 100644
--- a/core/undo_redo.h
+++ b/core/undo_redo.h
@@ -80,6 +80,7 @@ private:
int current_action;
int action_level;
MergeMode merge_mode;
+ bool merging;
uint64_t version;
void _pop_history_tail();
@@ -94,7 +95,7 @@ private:
MethodNotifyCallback method_callback;
PropertyNotifyCallback property_callback;
- int commiting;
+ int committing;
protected:
static void _bind_methods();
@@ -109,7 +110,7 @@ public:
void add_do_reference(Object *p_object);
void add_undo_reference(Object *p_object);
- bool is_commiting_action() const;
+ bool is_committing_action() const;
void commit_action();
bool redo();
diff --git a/core/ustring.cpp b/core/ustring.cpp
index ff8fcaaaaf..954c39c150 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -123,6 +123,31 @@ const char *CharString::get_data() const {
return "";
}
+CharString &CharString::operator=(const char *p_cstr) {
+
+ copy_from(p_cstr);
+ return *this;
+}
+
+void CharString::copy_from(const char *p_cstr) {
+
+ if (!p_cstr) {
+ resize(0);
+ return;
+ }
+
+ size_t len = strlen(p_cstr);
+
+ if (len == 0) {
+ resize(0);
+ return;
+ }
+
+ resize(len + 1); // include terminating null char
+
+ strcpy(ptrw(), p_cstr);
+}
+
void String::copy_from(const char *p_cstr) {
if (!p_cstr) {
@@ -1700,6 +1725,45 @@ int64_t String::hex_to_int64(bool p_with_prefix) const {
return hex * sign;
}
+int64_t String::bin_to_int64(bool p_with_prefix) const {
+
+ if (p_with_prefix && length() < 3)
+ return 0;
+
+ const CharType *s = ptr();
+
+ int64_t sign = s[0] == '-' ? -1 : 1;
+
+ if (sign < 0) {
+ s++;
+ }
+
+ if (p_with_prefix) {
+ if (s[0] != '0' || s[1] != 'b')
+ return 0;
+ s += 2;
+ }
+
+ int64_t binary = 0;
+
+ while (*s) {
+
+ CharType c = LOWERCASE(*s);
+ int64_t n;
+ if (c == '0' || c == '1') {
+ n = c - '0';
+ } else {
+ return 0;
+ }
+
+ binary *= 2;
+ binary += n;
+ s++;
+ }
+
+ return binary * sign;
+}
+
int String::to_int() const {
if (length() == 0)
@@ -3748,6 +3812,24 @@ bool String::is_valid_html_color() const {
return Color::html_is_valid(*this);
}
+bool String::is_valid_filename() const {
+
+ String stripped = strip_edges();
+ if (*this != stripped) {
+ return false;
+ }
+
+ if (stripped == String()) {
+ return false;
+ }
+
+ if (find(":") != -1 || find("/") != -1 || find("\\") != -1 || find("?") != -1 || find("*") != -1 || find("\"") != -1 || find("|") != -1 || find("%") != -1 || find("<") != -1 || find(">") != -1) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
bool String::is_valid_ip_address() const {
if (find(":") >= 0) {
diff --git a/core/ustring.h b/core/ustring.h
index cb3d87378a..be6300ac5b 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -97,12 +97,21 @@ public:
_FORCE_INLINE_ CharString() {}
_FORCE_INLINE_ CharString(const CharString &p_str) { _cowdata._ref(p_str._cowdata); }
+ _FORCE_INLINE_ CharString operator=(const CharString &p_str) {
+ _cowdata._ref(p_str._cowdata);
+ return *this;
+ }
+ _FORCE_INLINE_ CharString(const char *p_cstr) { copy_from(p_cstr); }
+ CharString &operator=(const char *p_cstr);
bool operator<(const CharString &p_right) const;
CharString &operator+=(char p_char);
int length() const { return size() ? size() - 1 : 0; }
const char *get_data() const;
operator const char *() const { return get_data(); };
+
+protected:
+ void copy_from(const char *p_cstr);
};
typedef wchar_t CharType;
@@ -242,6 +251,7 @@ public:
int to_int() const;
int64_t hex_to_int64(bool p_with_prefix = true) const;
+ int64_t bin_to_int64(bool p_with_prefix = true) const;
int64_t to_int64() const;
static int to_int(const char *p_str, int p_len = -1);
static double to_double(const char *p_str);
@@ -331,6 +341,7 @@ public:
bool is_valid_hex_number(bool p_with_prefix) const;
bool is_valid_html_color() const;
bool is_valid_ip_address() const;
+ bool is_valid_filename() const;
/**
* The constructors must not depend on other overloads
@@ -339,6 +350,10 @@ public:
_FORCE_INLINE_ String() {}
_FORCE_INLINE_ String(const String &p_str) { _cowdata._ref(p_str._cowdata); }
+ String operator=(const String &p_str) {
+ _cowdata._ref(p_str._cowdata);
+ return *this;
+ }
String(const char *p_str);
String(const CharType *p_str, int p_clip_to_len = -1);
@@ -398,11 +413,18 @@ _FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
//tool translate
#ifdef TOOLS_ENABLED
+//gets parsed
String TTR(const String &);
+//use for c strings
+#define TTRC(m_value) m_value
+//use to avoid parsing (for use later with C strings)
+#define TTRGET(m_value) TTR(m_value)
#else
#define TTR(m_val) (String())
+#define TTRCDEF(m_value) (m_value)
+#define TTRC(m_value) (m_value)
#endif
diff --git a/core/variant.cpp b/core/variant.cpp
index 2ee2e8e293..6eadf59fce 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -179,7 +179,8 @@ String Variant::get_type_name(Variant::Type p_type) {
return "PoolColorArray";
} break;
- default: {}
+ default: {
+ }
}
return "";
@@ -403,7 +404,8 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) {
valid_types = valid;
} break;
- default: {}
+ default: {
+ }
}
if (valid_types) {
@@ -649,7 +651,8 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
valid_types = valid;
} break;
- default: {}
+ default: {
+ }
}
if (valid_types) {
@@ -841,7 +844,8 @@ bool Variant::is_zero() const {
return reinterpret_cast<const PoolVector<Color> *>(_data._mem)->size() == 0;
} break;
- default: {}
+ default: {
+ }
}
return false;
@@ -896,7 +900,9 @@ bool Variant::is_one() const {
} break;
- default: { return !is_zero(); }
+ default: {
+ return !is_zero();
+ }
}
return false;
@@ -1039,7 +1045,8 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._mem, PoolVector<Color>(*reinterpret_cast<const PoolVector<Color> *>(p_variant._data._mem)));
} break;
- default: {}
+ default: {
+ }
}
}
@@ -1143,7 +1150,8 @@ void Variant::clear() {
reinterpret_cast<PoolVector<Color> *>(_data._mem)->~PoolVector<Color>();
} break;
- default: {} /* not needed */
+ default: {
+ } /* not needed */
}
type = NIL;
@@ -1407,7 +1415,12 @@ struct _VariantStrPair {
};
Variant::operator String() const {
+ List<const void *> stack;
+ return stringify(stack);
+}
+
+String Variant::stringify(List<const void *> &stack) const {
switch (type) {
case NIL: return "Null";
@@ -1459,6 +1472,12 @@ Variant::operator String() const {
case DICTIONARY: {
const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem);
+ if (stack.find(d.id())) {
+ return "{...}";
+ }
+
+ stack.push_back(d.id());
+
//const String *K=NULL;
String str("{");
List<Variant> keys;
@@ -1469,8 +1488,9 @@ Variant::operator String() const {
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
_VariantStrPair sp;
- sp.key = String(E->get());
- sp.value = d[E->get()];
+ sp.key = E->get().stringify(stack);
+ sp.value = d[E->get()].stringify(stack);
+
pairs.push_back(sp);
}
@@ -1553,12 +1573,19 @@ Variant::operator String() const {
case ARRAY: {
Array arr = operator Array();
+ if (stack.find(arr.id())) {
+ return "[...]";
+ }
+ stack.push_back(arr.id());
+
String str("[");
for (int i = 0; i < arr.size(); i++) {
if (i)
str += ", ";
- str += String(arr[i]);
- };
+
+ str += arr[i].stringify(stack);
+ }
+
str += "]";
return str;
@@ -1574,7 +1601,7 @@ Variant::operator String() const {
};
};
#endif
- return "[" + _get_obj().obj->get_class() + ":" + itos(_get_obj().obj->get_instance_id()) + "]";
+ return _get_obj().obj->to_string();
} else
return "[Object:null]";
@@ -1823,7 +1850,9 @@ inline DA _convert_array_from_variant(const Variant &p_variant) {
case Variant::POOL_COLOR_ARRAY: {
return _convert_array<DA, PoolVector<Color> >(p_variant.operator PoolVector<Color>());
}
- default: { return DA(); }
+ default: {
+ return DA();
+ }
}
return DA();
@@ -2642,7 +2671,8 @@ void Variant::operator=(const Variant &p_variant) {
*reinterpret_cast<PoolVector<Color> *>(_data._mem) = *reinterpret_cast<const PoolVector<Color> *>(p_variant._data._mem);
} break;
- default: {}
+ default: {
+ }
}
}
@@ -2919,7 +2949,8 @@ uint32_t Variant::hash() const {
return hash;
} break;
- default: {}
+ default: {
+ }
}
return 0;
@@ -3167,7 +3198,8 @@ bool Variant::is_shared() const {
case OBJECT: return true;
case ARRAY: return true;
case DICTIONARY: return true;
- default: {}
+ default: {
+ }
}
return false;
@@ -3204,7 +3236,8 @@ Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
String err = "Too many arguments for method '" + p_method + "'";
ERR_PRINT(err.utf8().get_data());
} break;
- default: {}
+ default: {
+ }
}
return ret;
diff --git a/core/variant.h b/core/variant.h
index 9215d15bf0..5151262f27 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -401,6 +401,7 @@ public:
bool hash_compare(const Variant &p_variant) const;
bool booleanize() const;
+ String stringify(List<const void *> &stack) const;
void static_assign(const Variant &p_variant);
static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list);
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 25a0f3957c..f9f73b4e51 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -36,6 +36,7 @@
#include "core/object.h"
#include "core/os/os.h"
#include "core/script_language.h"
+#include "thirdparty/misc/sha256.h"
typedef void (*VariantFunc)(Variant &r_ret, Variant &p_self, const Variant **p_args);
typedef void (*VariantConstructFunc)(Variant &r_ret, const Variant **p_args);
@@ -294,6 +295,7 @@ struct _VariantCall {
VCALL_LOCALMEM1R(String, is_valid_hex_number);
VCALL_LOCALMEM0R(String, is_valid_html_color);
VCALL_LOCALMEM0R(String, is_valid_ip_address);
+ VCALL_LOCALMEM0R(String, is_valid_filename);
VCALL_LOCALMEM0R(String, to_int);
VCALL_LOCALMEM0R(String, to_float);
VCALL_LOCALMEM0R(String, hex_to_int);
@@ -341,6 +343,7 @@ struct _VariantCall {
VCALL_LOCALMEM1R(Vector2, project);
VCALL_LOCALMEM1R(Vector2, angle_to);
VCALL_LOCALMEM1R(Vector2, angle_to_point);
+ VCALL_LOCALMEM1R(Vector2, direction_to);
VCALL_LOCALMEM2R(Vector2, linear_interpolate);
VCALL_LOCALMEM2R(Vector2, slerp);
VCALL_LOCALMEM4R(Vector2, cubic_interpolate);
@@ -397,6 +400,7 @@ struct _VariantCall {
VCALL_LOCALMEM1R(Vector3, distance_squared_to);
VCALL_LOCALMEM1R(Vector3, project);
VCALL_LOCALMEM1R(Vector3, angle_to);
+ VCALL_LOCALMEM1R(Vector3, direction_to);
VCALL_LOCALMEM1R(Vector3, slide);
VCALL_LOCALMEM1R(Vector3, bounce);
VCALL_LOCALMEM1R(Vector3, reflect);
@@ -584,6 +588,19 @@ struct _VariantCall {
r_ret = decompressed;
}
+ static void _call_PoolByteArray_sha256_string(Variant &r_ret, Variant &p_self, const Variant **p_args) {
+ PoolByteArray *ba = reinterpret_cast<PoolByteArray *>(p_self._data._mem);
+ PoolByteArray::Read r = ba->read();
+ String s;
+ unsigned char hash[32];
+ sha256_context sha256;
+ sha256_init(&sha256);
+ sha256_hash(&sha256, (unsigned char *)r.ptr(), ba->size());
+ sha256_done(&sha256, hash);
+ s = String::hex_encode_buffer(hash, 32);
+ r_ret = s;
+ }
+
VCALL_LOCALMEM0R(PoolByteArray, size);
VCALL_LOCALMEM2(PoolByteArray, set);
VCALL_LOCALMEM1R(PoolByteArray, get);
@@ -773,6 +790,8 @@ struct _VariantCall {
VCALL_PTR0R(Basis, get_orthogonal_index);
VCALL_PTR0R(Basis, orthonormalized);
VCALL_PTR2R(Basis, slerp);
+ VCALL_PTR2R(Basis, is_equal_approx);
+ VCALL_PTR0R(Basis, get_rotation_quat);
VCALL_PTR0R(Transform, inverse);
VCALL_PTR0R(Transform, affine_inverse);
@@ -1538,6 +1557,7 @@ void register_variant_methods() {
ADDFUNC1R(STRING, BOOL, String, is_valid_hex_number, BOOL, "with_prefix", varray(false));
ADDFUNC0R(STRING, BOOL, String, is_valid_html_color, varray());
ADDFUNC0R(STRING, BOOL, String, is_valid_ip_address, varray());
+ ADDFUNC0R(STRING, BOOL, String, is_valid_filename, varray());
ADDFUNC0R(STRING, INT, String, to_int, varray());
ADDFUNC0R(STRING, REAL, String, to_float, varray());
ADDFUNC0R(STRING, INT, String, hex_to_int, varray());
@@ -1554,6 +1574,7 @@ void register_variant_methods() {
ADDFUNC0R(VECTOR2, REAL, Vector2, angle, varray());
ADDFUNC0R(VECTOR2, REAL, Vector2, length_squared, varray());
ADDFUNC0R(VECTOR2, BOOL, Vector2, is_normalized, varray());
+ ADDFUNC1R(VECTOR2, VECTOR2, Vector2, direction_to, VECTOR2, "b", varray());
ADDFUNC1R(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray());
ADDFUNC1R(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray());
ADDFUNC1R(VECTOR2, VECTOR2, Vector2, project, VECTOR2, "b", varray());
@@ -1602,6 +1623,7 @@ void register_variant_methods() {
ADDFUNC2R(VECTOR3, VECTOR3, Vector3, linear_interpolate, VECTOR3, "b", REAL, "t", varray());
ADDFUNC2R(VECTOR3, VECTOR3, Vector3, slerp, VECTOR3, "b", REAL, "t", varray());
ADDFUNC4R(VECTOR3, VECTOR3, Vector3, cubic_interpolate, VECTOR3, "b", VECTOR3, "pre_a", VECTOR3, "post_b", REAL, "t", varray());
+ ADDFUNC1R(VECTOR3, VECTOR3, Vector3, direction_to, VECTOR3, "b", varray());
ADDFUNC1R(VECTOR3, REAL, Vector3, dot, VECTOR3, "b", varray());
ADDFUNC1R(VECTOR3, VECTOR3, Vector3, cross, VECTOR3, "b", varray());
ADDFUNC1R(VECTOR3, BASIS, Vector3, outer, VECTOR3, "b", varray());
@@ -1725,6 +1747,7 @@ void register_variant_methods() {
ADDFUNC0R(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_ascii, varray());
ADDFUNC0R(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_utf8, varray());
+ ADDFUNC0R(POOL_BYTE_ARRAY, STRING, PoolByteArray, sha256_string, varray());
ADDFUNC1R(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, compress, INT, "compression_mode", varray(0));
ADDFUNC2R(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, decompress, INT, "buffer_size", INT, "compression_mode", varray(0));
@@ -1842,6 +1865,8 @@ void register_variant_methods() {
ADDFUNC1R(BASIS, VECTOR3, Basis, xform_inv, VECTOR3, "v", varray());
ADDFUNC0R(BASIS, INT, Basis, get_orthogonal_index, varray());
ADDFUNC2R(BASIS, BASIS, Basis, slerp, BASIS, "b", REAL, "t", varray());
+ ADDFUNC2R(BASIS, BOOL, Basis, is_equal_approx, BASIS, "b", REAL, "epsilon", varray(CMP_EPSILON));
+ ADDFUNC0R(BASIS, QUAT, Basis, get_rotation_quat, varray());
ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, inverse, varray());
ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, affine_inverse, varray());
@@ -1923,9 +1948,9 @@ void register_variant_methods() {
_VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform);
transform_x.set(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
_VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", transform_x);
- transform_x.set(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
+ transform_y.set(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
_VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", transform_y);
- transform_x.set(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
+ transform_z.set(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
_VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", transform_z);
_VariantCall::add_variant_constant(Variant::PLANE, "PLANE_YZ", Plane(Vector3(1, 0, 0), 0));
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
index b40b6ce4a6..f3c9bcaa7e 100644
--- a/core/variant_op.cpp
+++ b/core/variant_op.cpp
@@ -2781,7 +2781,8 @@ bool Variant::in(const Variant &p_index, bool *r_valid) const {
return false;
}
} break;
- default: {}
+ default: {
+ }
}
if (r_valid)
@@ -2912,7 +2913,8 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const {
//nothing
} break;
- default: {}
+ default: {
+ }
}
}
@@ -3251,7 +3253,8 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const {
r_iter = idx;
return true;
} break;
- default: {}
+ default: {
+ }
}
valid = false;
@@ -3408,7 +3411,8 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
#endif
return arr->get(idx);
} break;
- default: {}
+ default: {
+ }
}
r_valid = false;
diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp
index 0056fc75b6..d7371b0434 100644
--- a/core/variant_parser.cpp
+++ b/core/variant_parser.cpp
@@ -1542,6 +1542,9 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r
} else if (c != '=') {
what += String::chr(c);
} else {
+ if (p_stream->is_utf8()) {
+ what.parse_utf8(what.ascii(true).get_data());
+ }
r_assign = what;
Token token;
get_token(p_stream, token, line, r_err_str);
@@ -1948,7 +1951,8 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
p_store_string_func(p_store_string_ud, " )");
} break;
- default: {}
+ default: {
+ }
}
return OK;
diff --git a/core/vmap.h b/core/vmap.h
index f46ed70a0f..fde9723d71 100644
--- a/core/vmap.h
+++ b/core/vmap.h
@@ -65,7 +65,7 @@ private:
const Pair *a = _cowdata.ptr();
int middle = 0;
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
if (low > high)
ERR_PRINT("low > high, this may be a bug");
#endif
diff --git a/core/vset.h b/core/vset.h
index 678ec507ba..5f087a5a03 100644
--- a/core/vset.h
+++ b/core/vset.h
@@ -50,7 +50,7 @@ class VSet {
const T *a = &_data[0];
int middle = 0;
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
if (low > high)
ERR_PRINT("low > high, this may be a bug");
#endif