diff options
394 files changed, 6577 insertions, 4061 deletions
diff --git a/.gitignore b/.gitignore index 1292be06fd..ca96220570 100644 --- a/.gitignore +++ b/.gitignore @@ -242,8 +242,10 @@ xcuserdata/ [Rr]eleases/ x64/ x86/ -# Not build results, this is Theora source code. -!thirdparty/libtheora/x86/ + +# Do not ignore x86 folders anywhere under thirdparty libraries +!thirdparty/**/x86/ + [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index d0de39a79d..385cd2b2fd 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1124,8 +1124,12 @@ void ProjectSettings::set_setting(const String &p_setting, const Variant &p_valu set(p_setting, p_value); } -Variant ProjectSettings::get_setting(const String &p_setting) const { - return get(p_setting); +Variant ProjectSettings::get_setting(const String &p_setting, const Variant &p_default_value) const { + if (has_setting(p_setting)) { + return get(p_setting); + } else { + return p_default_value; + } } bool ProjectSettings::has_custom_feature(const String &p_feature) const { @@ -1158,7 +1162,7 @@ ProjectSettings::AutoloadInfo ProjectSettings::get_autoload(const StringName &p_ void ProjectSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting); ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &ProjectSettings::set_setting); - ClassDB::bind_method(D_METHOD("get_setting", "name"), &ProjectSettings::get_setting); + ClassDB::bind_method(D_METHOD("get_setting", "name", "default_value"), &ProjectSettings::get_setting, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("set_order", "name", "position"), &ProjectSettings::set_order); ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order); ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value); @@ -1277,7 +1281,6 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("physics/2d/run_on_separate_thread", false); GLOBAL_DEF("physics/3d/run_on_separate_thread", false); - GLOBAL_DEF("debug/disable_touch", false); GLOBAL_DEF("debug/settings/profiler/max_functions", 16384); custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1"); diff --git a/core/config/project_settings.h b/core/config/project_settings.h index 960dfe0395..2ffbda9cea 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -141,7 +141,7 @@ public: static const int CONFIG_VERSION = 5; void set_setting(const String &p_setting, const Variant &p_value); - Variant get_setting(const String &p_setting) const; + Variant get_setting(const String &p_setting, const Variant &p_default_value = Variant()) const; bool has_setting(String p_var) const; String localize_path(const String &p_path) const; diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 5812a24c4f..a0e3778dcc 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -252,63 +252,140 @@ Dictionary GDExtensionAPIDump::generate_extension_api() { } { - // Member offsets sizes. + // Member offsets, meta types and sizes. + +#define REAL_MEMBER_OFFSET(type, member) \ + { \ + type, \ + member, \ + "float", \ + sizeof(float), \ + "float", \ + sizeof(float), \ + "double", \ + sizeof(double), \ + "double", \ + sizeof(double), \ + } + +#define INT32_MEMBER_OFFSET(type, member) \ + { \ + type, \ + member, \ + "int32", \ + sizeof(int32_t), \ + "int32", \ + sizeof(int32_t), \ + "int32", \ + sizeof(int32_t), \ + "int32", \ + sizeof(int32_t), \ + } + +#define INT32_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \ + { \ + type, \ + member, \ + member_type, \ + sizeof(int32_t) * member_elems, \ + member_type, \ + sizeof(int32_t) * member_elems, \ + member_type, \ + sizeof(int32_t) * member_elems, \ + member_type, \ + sizeof(int32_t) * member_elems, \ + } + +#define REAL_BASED_BUILTIN_MEMBER_OFFSET(type, member, member_type, member_elems) \ + { \ + type, \ + member, \ + member_type, \ + sizeof(float) * member_elems, \ + member_type, \ + sizeof(float) * member_elems, \ + member_type, \ + sizeof(double) * member_elems, \ + member_type, \ + sizeof(double) * member_elems, \ + } + struct { Variant::Type type; const char *member; - uint32_t offset_32_bits_real_float; - uint32_t offset_64_bits_real_float; - uint32_t offset_32_bits_real_double; - uint32_t offset_64_bits_real_double; + const char *member_meta_32_bits_real_float; + const uint32_t member_size_32_bits_real_float; + const char *member_meta_64_bits_real_float; + const uint32_t member_size_64_bits_real_float; + const char *member_meta_32_bits_real_double; + const uint32_t member_size_32_bits_real_double; + const char *member_meta_64_bits_real_double; + const uint32_t member_size_64_bits_real_double; } member_offset_array[] = { - { Variant::VECTOR2, "x", 0, 0, 0, 0 }, - { Variant::VECTOR2, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) }, - { Variant::VECTOR2I, "x", 0, 0, 0, 0 }, - { Variant::VECTOR2I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) }, - { Variant::RECT2, "position", 0, 0, 0, 0 }, - { Variant::RECT2, "size", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, - { Variant::RECT2I, "position", 0, 0, 0, 0 }, - { Variant::RECT2I, "size", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) }, - { Variant::VECTOR3, "x", 0, 0, 0, 0 }, - { Variant::VECTOR3, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) }, - { Variant::VECTOR3, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, - { Variant::VECTOR3I, "x", 0, 0, 0, 0 }, - { Variant::VECTOR3I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) }, - { Variant::VECTOR3I, "z", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) }, - { Variant::TRANSFORM2D, "x", 0, 0, 0, 0 }, - { Variant::TRANSFORM2D, "y", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, - { Variant::TRANSFORM2D, "origin", 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) }, - { Variant::VECTOR4, "x", 0, 0, 0, 0 }, - { Variant::VECTOR4, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) }, - { Variant::VECTOR4, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, - { Variant::VECTOR4, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(double), 3 * sizeof(double) }, - { Variant::VECTOR4I, "x", 0, 0, 0, 0 }, - { Variant::VECTOR4I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) }, - { Variant::VECTOR4I, "z", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) }, - { Variant::VECTOR4I, "w", 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t) }, - { Variant::PLANE, "normal", 0, 0, 0, 0 }, - { Variant::PLANE, "d", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) }, - { Variant::QUATERNION, "x", 0, 0, 0, 0 }, - { Variant::QUATERNION, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) }, - { Variant::QUATERNION, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, - { Variant::QUATERNION, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(double), 3 * sizeof(double) }, - { Variant::AABB, "position", 0, 0, 0, 0 }, - { Variant::AABB, "size", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) }, - // Remember that basis vectors are flipped! - { Variant::BASIS, "x", 0, 0, 0, 0 }, - { Variant::BASIS, "y", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) }, - { Variant::BASIS, "z", vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(double), vec3_elems * 2 * sizeof(double) }, - { Variant::TRANSFORM3D, "basis", 0, 0, 0, 0 }, - { Variant::TRANSFORM3D, "origin", (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) }, - { Variant::PROJECTION, "x", 0, 0, 0, 0 }, - { Variant::PROJECTION, "y", vec4_elems * sizeof(float), vec4_elems * sizeof(float), vec4_elems * sizeof(double), vec4_elems * sizeof(double) }, - { Variant::PROJECTION, "z", vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(double), vec4_elems * 2 * sizeof(double) }, - { Variant::PROJECTION, "w", vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(double), vec4_elems * 3 * sizeof(double) }, - { Variant::COLOR, "r", 0, 0, 0, 0 }, - { Variant::COLOR, "g", sizeof(float), sizeof(float), sizeof(float), sizeof(float) }, - { Variant::COLOR, "b", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float) }, - { Variant::COLOR, "a", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float) }, - { Variant::NIL, nullptr, 0, 0, 0, 0 }, + // Vector2 + REAL_MEMBER_OFFSET(Variant::VECTOR2, "x"), + REAL_MEMBER_OFFSET(Variant::VECTOR2, "y"), + // Vector2i + INT32_MEMBER_OFFSET(Variant::VECTOR2I, "x"), + INT32_MEMBER_OFFSET(Variant::VECTOR2I, "y"), + // Rect2 + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2, "position", "Vector2", 2), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2, "size", "Vector2", 2), + // Rect2i + INT32_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2I, "position", "Vector2i", 2), + INT32_BASED_BUILTIN_MEMBER_OFFSET(Variant::RECT2I, "size", "Vector2i", 2), + // Vector3 + REAL_MEMBER_OFFSET(Variant::VECTOR3, "x"), + REAL_MEMBER_OFFSET(Variant::VECTOR3, "y"), + REAL_MEMBER_OFFSET(Variant::VECTOR3, "z"), + // Vector3i + INT32_MEMBER_OFFSET(Variant::VECTOR3I, "x"), + INT32_MEMBER_OFFSET(Variant::VECTOR3I, "y"), + INT32_MEMBER_OFFSET(Variant::VECTOR3I, "z"), + // Transform2D + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM2D, "x", "Vector2", 2), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM2D, "y", "Vector2", 2), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM2D, "origin", "Vector2", 2), + // Vector4 + REAL_MEMBER_OFFSET(Variant::VECTOR4, "x"), + REAL_MEMBER_OFFSET(Variant::VECTOR4, "y"), + REAL_MEMBER_OFFSET(Variant::VECTOR4, "z"), + REAL_MEMBER_OFFSET(Variant::VECTOR4, "w"), + // Vector4i + INT32_MEMBER_OFFSET(Variant::VECTOR4I, "x"), + INT32_MEMBER_OFFSET(Variant::VECTOR4I, "y"), + INT32_MEMBER_OFFSET(Variant::VECTOR4I, "z"), + INT32_MEMBER_OFFSET(Variant::VECTOR4I, "w"), + // Plane + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PLANE, "normal", "Vector3", vec3_elems), + REAL_MEMBER_OFFSET(Variant::PLANE, "d"), + // Quaternion + REAL_MEMBER_OFFSET(Variant::QUATERNION, "x"), + REAL_MEMBER_OFFSET(Variant::QUATERNION, "y"), + REAL_MEMBER_OFFSET(Variant::QUATERNION, "z"), + REAL_MEMBER_OFFSET(Variant::QUATERNION, "w"), + // AABB + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::AABB, "position", "Vector3", vec3_elems), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::AABB, "size", "Vector3", vec3_elems), + // Basis (remember that basis vectors are flipped!) + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::BASIS, "x", "Vector3", vec3_elems), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::BASIS, "y", "Vector3", vec3_elems), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::BASIS, "z", "Vector3", vec3_elems), + // Transform3D + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM3D, "basis", "Basis", vec3_elems * 3), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::TRANSFORM3D, "origin", "Vector3", vec3_elems), + // Projection + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "x", "Vector4", vec4_elems), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "y", "Vector4", vec4_elems), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "z", "Vector4", vec4_elems), + REAL_BASED_BUILTIN_MEMBER_OFFSET(Variant::PROJECTION, "w", "Vector4", vec4_elems), + // Color (always composed of 4bytes floats) + { Variant::COLOR, "r", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) }, + { Variant::COLOR, "g", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) }, + { Variant::COLOR, "b", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) }, + { Variant::COLOR, "a", "float", sizeof(float), "float", sizeof(float), "float", sizeof(float), "float", sizeof(float) }, + // End marker, must stay last + { Variant::NIL, nullptr, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0 }, }; Array core_type_member_offsets; @@ -319,15 +396,16 @@ Dictionary GDExtensionAPIDump::generate_extension_api() { Array type_offsets; uint32_t idx = 0; - Variant::Type last_type = Variant::NIL; + Variant::Type previous_type = Variant::NIL; Dictionary d2; Array members; + uint32_t offset = 0; while (true) { Variant::Type t = member_offset_array[idx].type; - if (t != last_type) { - if (last_type != Variant::NIL) { + if (t != previous_type) { + if (previous_type != Variant::NIL) { d2["members"] = members; type_offsets.push_back(d2); } @@ -338,27 +416,35 @@ Dictionary GDExtensionAPIDump::generate_extension_api() { String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t); d2 = Dictionary(); members = Array(); + offset = 0; d2["name"] = name; - last_type = t; + previous_type = t; } Dictionary d3; - uint32_t offset = 0; + const char *member_meta = nullptr; + uint32_t member_size = 0; switch (i) { case 0: - offset = member_offset_array[idx].offset_32_bits_real_float; + member_meta = member_offset_array[idx].member_meta_32_bits_real_float; + member_size = member_offset_array[idx].member_size_32_bits_real_float; break; case 1: - offset = member_offset_array[idx].offset_64_bits_real_float; + member_meta = member_offset_array[idx].member_meta_64_bits_real_float; + member_size = member_offset_array[idx].member_size_64_bits_real_float; break; case 2: - offset = member_offset_array[idx].offset_32_bits_real_double; + member_meta = member_offset_array[idx].member_meta_32_bits_real_double; + member_size = member_offset_array[idx].member_size_32_bits_real_double; break; case 3: - offset = member_offset_array[idx].offset_64_bits_real_double; + member_meta = member_offset_array[idx].member_meta_64_bits_real_double; + member_size = member_offset_array[idx].member_size_64_bits_real_double; break; } d3["member"] = member_offset_array[idx].member; d3["offset"] = offset; + d3["meta"] = member_meta; + offset += member_size; members.push_back(d3); idx++; } diff --git a/core/io/image.cpp b/core/io/image.cpp index 1b9538794a..a2e1bc22be 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -173,6 +173,14 @@ int Image::get_format_pixel_size(Format p_format) { return 1; case FORMAT_DXT5_RA_AS_RG: return 1; + case FORMAT_ASTC_4x4: + return 1; + case FORMAT_ASTC_4x4_HDR: + return 1; + case FORMAT_ASTC_8x8: + return 1; + case FORMAT_ASTC_8x8_HDR: + return 1; case FORMAT_MAX: { } } @@ -213,7 +221,18 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) { r_h = 4; } break; + case FORMAT_ASTC_4x4: + case FORMAT_ASTC_4x4_HDR: { + r_w = 4; + r_h = 4; + + } break; + case FORMAT_ASTC_8x8: + case FORMAT_ASTC_8x8_HDR: { + r_w = 8; + r_h = 8; + } break; default: { r_w = 1; r_h = 1; @@ -222,7 +241,9 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) { } int Image::get_format_pixel_rshift(Format p_format) { - if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) { + if (p_format == FORMAT_ASTC_8x8) { + return 2; + } else if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) { return 1; } else { return 0; @@ -260,6 +281,14 @@ int Image::get_format_block_size(Format p_format) { { return 4; } + case FORMAT_ASTC_4x4: + case FORMAT_ASTC_4x4_HDR: { + return 4; + } + case FORMAT_ASTC_8x8: + case FORMAT_ASTC_8x8_HDR: { + return 8; + } default: { } } @@ -2581,19 +2610,23 @@ Error Image::decompress() { _image_decompress_etc1(this); } else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RA_AS_RG && _image_decompress_etc2) { _image_decompress_etc2(this); + } else if (format >= FORMAT_ASTC_4x4 && format <= FORMAT_ASTC_8x8_HDR && _image_decompress_astc) { + _image_decompress_astc(this); } else { return ERR_UNAVAILABLE; } return OK; } -Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality) { +Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality, ASTCFormat p_astc_format) { ERR_FAIL_INDEX_V_MSG(p_mode, COMPRESS_MAX, ERR_INVALID_PARAMETER, "Invalid compress mode."); ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source."); - return compress_from_channels(p_mode, detect_used_channels(p_source), p_lossy_quality); + return compress_from_channels(p_mode, detect_used_channels(p_source), p_lossy_quality, p_astc_format); } -Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality) { +Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality, ASTCFormat p_astc_format) { + ERR_FAIL_COND_V(data.is_empty(), ERR_INVALID_DATA); + switch (p_mode) { case COMPRESS_S3TC: { ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE); @@ -2611,6 +2644,10 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE); _image_compress_bptc_func(this, p_lossy_quality, p_channels); } break; + case COMPRESS_ASTC: { + ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE); + _image_compress_astc_func(this, p_lossy_quality, p_astc_format); + } break; case COMPRESS_MAX: { ERR_FAIL_V(ERR_INVALID_PARAMETER); } break; @@ -2967,10 +3004,12 @@ void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = nu void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = nullptr; void (*Image::_image_compress_etc1_func)(Image *, float) = nullptr; void (*Image::_image_compress_etc2_func)(Image *, float, Image::UsedChannels) = nullptr; +void (*Image::_image_compress_astc_func)(Image *, float, Image::ASTCFormat) = nullptr; void (*Image::_image_decompress_bc)(Image *) = nullptr; void (*Image::_image_decompress_bptc)(Image *) = nullptr; void (*Image::_image_decompress_etc1)(Image *) = nullptr; void (*Image::_image_decompress_etc2)(Image *) = nullptr; +void (*Image::_image_decompress_astc)(Image *) = nullptr; Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr; Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr; @@ -3387,8 +3426,8 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible); ClassDB::bind_method(D_METHOD("detect_used_channels", "source"), &Image::detect_used_channels, DEFVAL(COMPRESS_SOURCE_GENERIC)); - ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(0.7)); - ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality"), &Image::compress_from_channels, DEFVAL(0.7)); + ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality", "astc_format"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(0.7), DEFVAL(ASTC_FORMAT_4x4)); + ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality", "astc_format"), &Image::compress_from_channels, DEFVAL(0.7), DEFVAL(ASTC_FORMAT_4x4)); ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress); ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed); @@ -3472,6 +3511,10 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(FORMAT_ETC2_RGB8A1); BIND_ENUM_CONSTANT(FORMAT_ETC2_RA_AS_RG); BIND_ENUM_CONSTANT(FORMAT_DXT5_RA_AS_RG); + BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4); + BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4_HDR); + BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8); + BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8_HDR); BIND_ENUM_CONSTANT(FORMAT_MAX); BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST); @@ -3499,6 +3542,9 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(COMPRESS_SOURCE_GENERIC); BIND_ENUM_CONSTANT(COMPRESS_SOURCE_SRGB); BIND_ENUM_CONSTANT(COMPRESS_SOURCE_NORMAL); + + BIND_ENUM_CONSTANT(ASTC_FORMAT_4x4); + BIND_ENUM_CONSTANT(ASTC_FORMAT_8x8); } void Image::set_compress_bc_func(void (*p_compress_func)(Image *, float, UsedChannels)) { diff --git a/core/io/image.h b/core/io/image.h index ad5c0b4a04..8bcee4404b 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -109,6 +109,10 @@ public: FORMAT_ETC2_RGB8A1, FORMAT_ETC2_RA_AS_RG, //used to make basis universal happy FORMAT_DXT5_RA_AS_RG, //used to make basis universal happy + FORMAT_ASTC_4x4, + FORMAT_ASTC_4x4_HDR, + FORMAT_ASTC_8x8, + FORMAT_ASTC_8x8_HDR, FORMAT_MAX }; @@ -134,6 +138,11 @@ public: }; //some functions provided by something else + enum ASTCFormat { + ASTC_FORMAT_4x4, + ASTC_FORMAT_8x8, + }; + static ImageMemLoadFunc _png_mem_loader_func; static ImageMemLoadFunc _jpg_mem_loader_func; static ImageMemLoadFunc _webp_mem_loader_func; @@ -144,11 +153,13 @@ public: static void (*_image_compress_bptc_func)(Image *, float p_lossy_quality, UsedChannels p_channels); static void (*_image_compress_etc1_func)(Image *, float); static void (*_image_compress_etc2_func)(Image *, float, UsedChannels p_channels); + static void (*_image_compress_astc_func)(Image *, float, ASTCFormat p_format); static void (*_image_decompress_bc)(Image *); static void (*_image_decompress_bptc)(Image *); static void (*_image_decompress_etc1)(Image *); static void (*_image_decompress_etc2)(Image *); + static void (*_image_decompress_astc)(Image *); static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality); static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image); @@ -347,6 +358,7 @@ public: COMPRESS_ETC, COMPRESS_ETC2, COMPRESS_BPTC, + COMPRESS_ASTC, COMPRESS_MAX, }; enum CompressSource { @@ -356,8 +368,8 @@ public: COMPRESS_SOURCE_MAX, }; - Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7); - Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality = 0.7); + Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7, ASTCFormat p_astc_format = ASTC_FORMAT_4x4); + Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality = 0.7, ASTCFormat p_astc_format = ASTC_FORMAT_4x4); Error decompress(); bool is_compressed() const; @@ -429,5 +441,6 @@ VARIANT_ENUM_CAST(Image::CompressSource) VARIANT_ENUM_CAST(Image::UsedChannels) VARIANT_ENUM_CAST(Image::AlphaMode) VARIANT_ENUM_CAST(Image::RoughnessChannel) +VARIANT_ENUM_CAST(Image::ASTCFormat) #endif // IMAGE_H diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp index c30acf32bb..968102e323 100644 --- a/core/math/a_star_grid_2d.cpp +++ b/core/math/a_star_grid_2d.cpp @@ -155,6 +155,19 @@ bool AStarGrid2D::is_point_solid(const Vector2i &p_id) const { return points[p_id.y][p_id.x].solid; } +void AStarGrid2D::set_point_weight_scale(const Vector2i &p_id, real_t p_weight_scale) { + ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method."); + ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set point's weight scale. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height)); + ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't set point's weight scale less than 0.0: %f.", p_weight_scale)); + points[p_id.y][p_id.x].weight_scale = p_weight_scale; +} + +real_t AStarGrid2D::get_point_weight_scale(const Vector2i &p_id) const { + ERR_FAIL_COND_V_MSG(dirty, 0, "Grid is not initialized. Call the update method."); + ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), 0, vformat("Can't get point's weight scale. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height)); + return points[p_id.y][p_id.x].weight_scale; +} + AStarGrid2D::Point *AStarGrid2D::_jump(Point *p_from, Point *p_to) { if (!p_to || p_to->solid) { return nullptr; @@ -388,7 +401,10 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) { _get_nbors(p, nbors); for (List<Point *>::Element *E = nbors.front(); E; E = E->next()) { Point *e = E->get(); // The neighbour point. + real_t weight_scale = 1.0; + if (jumping_enabled) { + // TODO: Make it works with weight_scale. e = _jump(p, e); if (!e || e->closed_pass == pass) { continue; @@ -397,9 +413,10 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) { if (e->solid || e->closed_pass == pass) { continue; } + weight_scale = e->weight_scale; } - real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id); + real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * weight_scale; bool new_point = false; if (e->open_pass != pass) { // The point wasn't inside the open list. @@ -446,6 +463,12 @@ void AStarGrid2D::clear() { size = Vector2i(); } +Vector2 AStarGrid2D::get_point_position(const Vector2i &p_id) const { + ERR_FAIL_COND_V_MSG(dirty, Vector2(), "Grid is not initialized. Call the update method."); + ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), Vector2(), vformat("Can't get point's position. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height)); + return points[p_id.y][p_id.x].pos; +} + Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id) { ERR_FAIL_COND_V_MSG(dirty, Vector<Vector2>(), "Grid is not initialized. Call the update method."); ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height)); @@ -559,8 +582,11 @@ void AStarGrid2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_default_heuristic"), &AStarGrid2D::get_default_heuristic); ClassDB::bind_method(D_METHOD("set_point_solid", "id", "solid"), &AStarGrid2D::set_point_solid, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_point_solid", "id"), &AStarGrid2D::is_point_solid); + ClassDB::bind_method(D_METHOD("set_point_weight_scale", "id", "weight_scale"), &AStarGrid2D::set_point_weight_scale); + ClassDB::bind_method(D_METHOD("get_point_weight_scale", "id"), &AStarGrid2D::get_point_weight_scale); ClassDB::bind_method(D_METHOD("clear"), &AStarGrid2D::clear); + ClassDB::bind_method(D_METHOD("get_point_position", "id"), &AStarGrid2D::get_point_position); ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::get_point_path); ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::get_id_path); diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h index 1002f18738..3b39d46a20 100644 --- a/core/math/a_star_grid_2d.h +++ b/core/math/a_star_grid_2d.h @@ -72,6 +72,7 @@ private: bool solid = false; Vector2 pos; + real_t weight_scale = 1.0; // Used for pathfinding. Point *prev_point = nullptr; @@ -166,8 +167,12 @@ public: void set_point_solid(const Vector2i &p_id, bool p_solid = true); bool is_point_solid(const Vector2i &p_id) const; + void set_point_weight_scale(const Vector2i &p_id, real_t p_weight_scale); + real_t get_point_weight_scale(const Vector2i &p_id) const; + void clear(); + Vector2 get_point_position(const Vector2i &p_id) const; Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to); TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to); }; diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp index 561970d2ee..51d88d8ea0 100644 --- a/core/math/convex_hull.cpp +++ b/core/math/convex_hull.cpp @@ -2274,8 +2274,7 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3 // Copy the edges over. There's two "half-edges" for every edge, so we pick only one of them. r_mesh.edges.resize(ch.edges.size() / 2); - OAHashMap<uint64_t, int32_t> edge_map; - edge_map.reserve(ch.edges.size() * 4); // The higher the capacity, the faster the insert + OAHashMap<uint64_t, int32_t> edge_map(ch.edges.size() * 4); // The higher the capacity, the faster the insert uint32_t edges_copied = 0; for (uint32_t i = 0; i < ch.edges.size(); i++) { diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp index 9c4fc4e1b7..64d49b8b93 100644 --- a/core/string/string_name.cpp +++ b/core/string/string_name.cpp @@ -169,6 +169,10 @@ bool StringName::operator!=(const String &p_name) const { return !(operator==(p_name)); } +bool StringName::operator!=(const char *p_name) const { + return !(operator==(p_name)); +} + bool StringName::operator!=(const StringName &p_name) const { // the real magic of all this mess happens here. // this is why path comparisons are very fast diff --git a/core/string/string_name.h b/core/string/string_name.h index ff4c41af94..6a2420e02a 100644 --- a/core/string/string_name.h +++ b/core/string/string_name.h @@ -102,6 +102,7 @@ public: bool operator==(const String &p_name) const; bool operator==(const char *p_name) const; bool operator!=(const String &p_name) const; + bool operator!=(const char *p_name) const; _FORCE_INLINE_ bool is_node_unique_name() const { if (!_data) { diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 684baff348..f3b9bd235c 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -1314,7 +1314,7 @@ struct VariantZeroAssigner<float> { template <> struct VariantZeroAssigner<String> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_string(v) = String(); } }; template <> @@ -1399,12 +1399,12 @@ struct VariantZeroAssigner<Color> { template <> struct VariantZeroAssigner<StringName> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_string_name(v) = StringName(); } }; template <> struct VariantZeroAssigner<NodePath> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_node_path(v) = NodePath(); } }; template <> @@ -1414,12 +1414,12 @@ struct VariantZeroAssigner<::RID> { template <> struct VariantZeroAssigner<Callable> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_callable(v) = Callable(); } }; template <> struct VariantZeroAssigner<Signal> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_signal(v) = Signal(); } }; template <> @@ -1434,47 +1434,47 @@ struct VariantZeroAssigner<Array> { template <> struct VariantZeroAssigner<PackedByteArray> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_byte_array(v) = PackedByteArray(); } }; template <> struct VariantZeroAssigner<PackedInt32Array> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_int32_array(v) = PackedInt32Array(); } }; template <> struct VariantZeroAssigner<PackedInt64Array> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_int64_array(v) = PackedInt64Array(); } }; template <> struct VariantZeroAssigner<PackedFloat32Array> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float32_array(v) = PackedFloat32Array(); } }; template <> struct VariantZeroAssigner<PackedFloat64Array> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float64_array(v) = PackedFloat64Array(); } }; template <> struct VariantZeroAssigner<PackedStringArray> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_string_array(v) = PackedStringArray(); } }; template <> struct VariantZeroAssigner<PackedVector2Array> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector2_array(v) = PackedVector2Array(); } }; template <> struct VariantZeroAssigner<PackedVector3Array> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector3_array(v) = PackedVector3Array(); } }; template <> struct VariantZeroAssigner<PackedColorArray> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_color_array(v) = PackedColorArray(); } }; template <class T> diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml index bffa395770..cba783246f 100644 --- a/doc/classes/AStarGrid2D.xml +++ b/doc/classes/AStarGrid2D.xml @@ -69,6 +69,20 @@ [b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message. </description> </method> + <method name="get_point_position" qualifiers="const"> + <return type="Vector2" /> + <param index="0" name="id" type="Vector2i" /> + <description> + Returns the position of the point associated with the given [param id]. + </description> + </method> + <method name="get_point_weight_scale" qualifiers="const"> + <return type="float" /> + <param index="0" name="id" type="Vector2i" /> + <description> + Returns the weight scale of the point associated with the given [param id]. + </description> + </method> <method name="is_dirty" qualifiers="const"> <return type="bool" /> <description> @@ -106,6 +120,15 @@ [b]Note:[/b] Calling [method update] is not needed after the call of this function. </description> </method> + <method name="set_point_weight_scale"> + <return type="void" /> + <param index="0" name="id" type="Vector2i" /> + <param index="1" name="weight_scale" type="float" /> + <description> + Sets the [param weight_scale] for the point with the given [param id]. The [param weight_scale] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point. + [b]Note:[/b] Calling [method update] is not needed after the call of this function. + </description> + </method> <method name="update"> <return type="void" /> <description> @@ -125,6 +148,7 @@ </member> <member name="jumping_enabled" type="bool" setter="set_jumping_enabled" getter="is_jumping_enabled" default="false"> Enables or disables jumping to skip up the intermediate points and speeds up the searching algorithm. + [b]Note:[/b] Currently, toggling it on disables the consideration of weight scaling in pathfinding. </member> <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The offset of the grid which will be applied to calculate the resulting point position returned by [method get_point_path]. If changed, [method update] needs to be called before finding the next path. diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index d9a1f896f1..c0626dcfe4 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -305,9 +305,9 @@ <return type="int" /> <param index="0" name="track_idx" type="int" /> <param index="1" name="time" type="float" /> - <param index="2" name="exact" type="bool" default="false" /> + <param index="2" name="find_mode" type="int" enum="Animation.FindMode" default="0" /> <description> - Finds the key index by time in a given track. Optionally, only find it if the exact time is given. + Finds the key index by time in a given track. Optionally, only find it if the approx/exact time is given. </description> </method> <method name="track_get_interpolation_loop_wrap" qualifiers="const"> @@ -622,5 +622,14 @@ <constant name="LOOPED_FLAG_START" value="2" enum="LoopedFlag"> This flag indicates that the animation has reached the start of the animation and just after loop processed. </constant> + <constant name="FIND_MODE_NEAREST" value="0" enum="FindMode"> + Finds the nearest time key. + </constant> + <constant name="FIND_MODE_APPROX" value="1" enum="FindMode"> + Finds only the key with approximating the time. + </constant> + <constant name="FIND_MODE_EXACT" value="2" enum="FindMode"> + Finds only the key with matching the time. + </constant> </constants> </class> diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml index 4c2a30030b..814b2d0052 100644 --- a/doc/classes/AnimationNodeStateMachineTransition.xml +++ b/doc/classes/AnimationNodeStateMachineTransition.xml @@ -22,14 +22,11 @@ <member name="advance_expression" type="String" setter="set_advance_expression" getter="get_advance_expression" default=""""> Use an expression as a condition for state machine transitions. It is possible to create complex animation advance conditions for switching between states and gives much greater flexibility for creating complex state machines by directly interfacing with the script code. </member> - <member name="auto_advance" type="bool" setter="set_auto_advance" getter="has_auto_advance" default="false"> - Turn on the transition automatically when this state is reached. This works best with [constant SWITCH_MODE_AT_END]. - </member> - <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false"> - Don't use this transition during [method AnimationNodeStateMachinePlayback.travel] or [member auto_advance]. + <member name="advance_mode" type="int" setter="set_advance_mode" getter="get_advance_mode" enum="AnimationNodeStateMachineTransition.AdvanceMode" default="1"> + Determines whether the transition should disabled, enabled when using [method AnimationNodeStateMachinePlayback.travel], or traversed automatically if the [member advance_condition] and [member advance_expression] checks are true (if assigned). </member> <member name="priority" type="int" setter="set_priority" getter="get_priority" default="1"> - Lower priority transitions are preferred when travelling through the tree via [method AnimationNodeStateMachinePlayback.travel] or [member auto_advance]. + Lower priority transitions are preferred when travelling through the tree via [method AnimationNodeStateMachinePlayback.travel] or [member advance_mode] is set to [constant ADVANCE_MODE_AUTO]. </member> <member name="switch_mode" type="int" setter="set_switch_mode" getter="get_switch_mode" enum="AnimationNodeStateMachineTransition.SwitchMode" default="0"> The transition type. @@ -58,5 +55,14 @@ <constant name="SWITCH_MODE_AT_END" value="2" enum="SwitchMode"> Wait for the current state playback to end, then switch to the beginning of the next state animation. </constant> + <constant name="ADVANCE_MODE_DISABLED" value="0" enum="AdvanceMode"> + Don't use this transition. + </constant> + <constant name="ADVANCE_MODE_ENABLED" value="1" enum="AdvanceMode"> + Only use this transition during [method AnimationNodeStateMachinePlayback.travel]. + </constant> + <constant name="ADVANCE_MODE_AUTO" value="2" enum="AdvanceMode"> + Automatically use this transition if the [member advance_condition] and [member advance_expression] checks are true (if assigned). + </constant> </constants> </class> diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml index 21f4b37741..a17a727d7e 100644 --- a/doc/classes/AnimationTree.xml +++ b/doc/classes/AnimationTree.xml @@ -111,11 +111,25 @@ </member> </members> <signals> + <signal name="animation_finished"> + <param index="0" name="anim_name" type="StringName" /> + <description> + Notifies when an animation finished playing. + [b]Note:[/b] This signal is not emitted if an animation is looping or aborted. Also be aware of the possibility of unseen playback by sync and xfade. + </description> + </signal> <signal name="animation_player_changed"> <description> Emitted when the [member anim_player] is changed. </description> </signal> + <signal name="animation_started"> + <param index="0" name="anim_name" type="StringName" /> + <description> + Notifies when an animation starts playing. + [b]Note:[/b] This signal is not emitted if an animation is looping or playbacked from the middle. Also be aware of the possibility of unseen playback by sync and xfade. + </description> + </signal> </signals> <constants> <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback"> diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml index 29592f133d..3f76cc16ec 100644 --- a/doc/classes/Area2D.xml +++ b/doc/classes/Area2D.xml @@ -114,15 +114,13 @@ <signal name="area_entered"> <param index="0" name="area" type="Area2D" /> <description> - Emitted when another Area2D enters this Area2D. Requires [member monitoring] to be set to [code]true[/code]. - [param area] the other Area2D. + Emitted when the received [param area] enters this area. Requires [member monitoring] to be set to [code]true[/code]. </description> </signal> <signal name="area_exited"> <param index="0" name="area" type="Area2D" /> <description> - Emitted when another Area2D exits this Area2D. Requires [member monitoring] to be set to [code]true[/code]. - [param area] the other Area2D. + Emitted when the received [param area] exits this area. Requires [member monitoring] to be set to [code]true[/code]. </description> </signal> <signal name="area_shape_entered"> @@ -131,11 +129,18 @@ <param index="2" name="area_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of another Area2D's [Shape2D]s enters one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code]. - [param area_rid] the [RID] of the other Area2D's [CollisionObject2D] used by the [PhysicsServer2D]. - [param area] the other Area2D. - [param area_shape_index] the index of the [Shape2D] of the other Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code]. - [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code]. + Emitted when a [Shape2D] of the received [param area] enters a shape of this area. Requires [member monitoring] to be set to [code]true[/code]. + [param local_shape_index] and [param area_shape_index] contain indices of the interacting shapes from this area and the other area, respectively. [param area_rid] contains the [RID] of the other area. These values can be used with the [PhysicsServer2D]. + [b]Example of getting the[/b] [CollisionShape2D] [b]node from the shape index:[/b] + [codeblocks] + [gdscript] + var other_shape_owner = area.shape_find_owner(area_shape_index) + var other_shape_node = area.shape_owner_get_owner(other_shape_owner) + + var local_shape_owner = shape_find_owner(local_shape_index) + var local_shape_node = shape_owner_get_owner(local_shape_owner) + [/gdscript] + [/codeblocks] </description> </signal> <signal name="area_shape_exited"> @@ -144,25 +149,20 @@ <param index="2" name="area_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of another Area2D's [Shape2D]s exits one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code]. - [param area_rid] the [RID] of the other Area2D's [CollisionObject2D] used by the [PhysicsServer2D]. - [param area] the other Area2D. - [param area_shape_index] the index of the [Shape2D] of the other Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code]. - [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code]. + Emitted when a [Shape2D] of the received [param area] exits a shape of this area. Requires [member monitoring] to be set to [code]true[/code]. + See also [signal area_shape_entered]. </description> </signal> <signal name="body_entered"> <param index="0" name="body" type="Node2D" /> <description> - Emitted when a [PhysicsBody2D] or [TileMap] enters this Area2D. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. - [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap]. + Emitted when the received [param body] enters this area. [param body] can be a [PhysicsBody2D] or a [TileMap]. [TileMap]s are detected if their [TileSet] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code]. </description> </signal> <signal name="body_exited"> <param index="0" name="body" type="Node2D" /> <description> - Emitted when a [PhysicsBody2D] or [TileMap] exits this Area2D. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. - [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap]. + Emitted when the received [param body] exits this area. [param body] can be a [PhysicsBody2D] or a [TileMap]. [TileMap]s are detected if their [TileSet] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code]. </description> </signal> <signal name="body_shape_entered"> @@ -171,11 +171,18 @@ <param index="2" name="body_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of a [PhysicsBody2D] or [TileMap]'s [Shape2D]s enters one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. - [param body_rid] the [RID] of the [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D]. - [param body] the [Node], if it exists in the tree, of the [PhysicsBody2D] or [TileMap]. - [param body_shape_index] the index of the [Shape2D] of the [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code]. - [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code]. + Emitted when a [Shape2D] of the received [param body] enters a shape of this area. [param body] can be a [PhysicsBody2D] or a [TileMap]. [TileMap]s are detected if their [TileSet] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code]. + [param local_shape_index] and [param body_shape_index] contain indices of the interacting shapes from this area and the interacting body, respectively. [param body_rid] contains the [RID] of the body. These values can be used with the [PhysicsServer2D]. + [b]Example of getting the[/b] [CollisionShape2D] [b]node from the shape index:[/b] + [codeblocks] + [gdscript] + var body_shape_owner = body.shape_find_owner(body_shape_index) + var body_shape_node = body.shape_owner_get_owner(body_shape_owner) + + var local_shape_owner = shape_find_owner(local_shape_index) + var local_shape_node = shape_owner_get_owner(local_shape_owner) + [/gdscript] + [/codeblocks] </description> </signal> <signal name="body_shape_exited"> @@ -184,11 +191,8 @@ <param index="2" name="body_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of a [PhysicsBody2D] or [TileMap]'s [Shape2D]s exits one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s. - [param body_rid] the [RID] of the [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D]. - [param body] the [Node], if it exists in the tree, of the [PhysicsBody2D] or [TileMap]. - [param body_shape_index] the index of the [Shape2D] of the [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code]. - [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code]. + Emitted when a [Shape2D] of the received [param body] exits a shape of this area. [param body] can be a [PhysicsBody2D] or a [TileMap]. [TileMap]s are detected if their [TileSet] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code]. + See also [signal body_shape_entered]. </description> </signal> </signals> diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml index ea8cab324d..8923ac8aae 100644 --- a/doc/classes/Area3D.xml +++ b/doc/classes/Area3D.xml @@ -133,15 +133,13 @@ <signal name="area_entered"> <param index="0" name="area" type="Area3D" /> <description> - Emitted when another Area3D enters this Area3D. Requires [member monitoring] to be set to [code]true[/code]. - [param area] the other Area3D. + Emitted when the received [param area] enters this area. Requires [member monitoring] to be set to [code]true[/code]. </description> </signal> <signal name="area_exited"> <param index="0" name="area" type="Area3D" /> <description> - Emitted when another Area3D exits this Area3D. Requires [member monitoring] to be set to [code]true[/code]. - [param area] the other Area3D. + Emitted when the received [param area] exits this area. Requires [member monitoring] to be set to [code]true[/code]. </description> </signal> <signal name="area_shape_entered"> @@ -150,11 +148,18 @@ <param index="2" name="area_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of another Area3D's [Shape3D]s enters one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code]. - [param area_rid] the [RID] of the other Area3D's [CollisionObject3D] used by the [PhysicsServer3D]. - [param area] the other Area3D. - [param area_shape_index] the index of the [Shape3D] of the other Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code]. - [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code]. + Emitted when a [Shape3D] of the received [param area] enters a shape of this area. Requires [member monitoring] to be set to [code]true[/code]. + [param local_shape_index] and [param area_shape_index] contain indices of the interacting shapes from this area and the other area, respectively. [param area_rid] contains the [RID] of the other area. These values can be used with the [PhysicsServer3D]. + [b]Example of getting the[/b] [CollisionShape3D] [b]node from the shape index:[/b] + [codeblocks] + [gdscript] + var other_shape_owner = area.shape_find_owner(area_shape_index) + var other_shape_node = area.shape_owner_get_owner(other_shape_owner) + + var local_shape_owner = shape_find_owner(local_shape_index) + var local_shape_node = shape_owner_get_owner(local_shape_owner) + [/gdscript] + [/codeblocks] </description> </signal> <signal name="area_shape_exited"> @@ -163,25 +168,20 @@ <param index="2" name="area_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of another Area3D's [Shape3D]s exits one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code]. - [param area_rid] the [RID] of the other Area3D's [CollisionObject3D] used by the [PhysicsServer3D]. - [param area] the other Area3D. - [param area_shape_index] the index of the [Shape3D] of the other Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code]. - [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code]. + Emitted when a [Shape3D] of the received [param area] exits a shape of this area. Requires [member monitoring] to be set to [code]true[/code]. + See also [signal area_shape_entered]. </description> </signal> <signal name="body_entered"> <param index="0" name="body" type="Node3D" /> <description> - Emitted when a [PhysicsBody3D] or [GridMap] enters this Area3D. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. - [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap]. + Emitted when the received [param body] enters this area. [param body] can be a [PhysicsBody3D] or a [GridMap]. [GridMap]s are detected if their [MeshLibrary] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code]. </description> </signal> <signal name="body_exited"> <param index="0" name="body" type="Node3D" /> <description> - Emitted when a [PhysicsBody3D] or [GridMap] exits this Area3D. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. - [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap]. + Emitted when the received [param body] exits this area. [param body] can be a [PhysicsBody3D] or a [GridMap]. [GridMap]s are detected if their [MeshLibrary] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code]. </description> </signal> <signal name="body_shape_entered"> @@ -190,11 +190,18 @@ <param index="2" name="body_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of a [PhysicsBody3D] or [GridMap]'s [Shape3D]s enters one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. - [param body_rid] the [RID] of the [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D]. - [param body] the [Node], if it exists in the tree, of the [PhysicsBody3D] or [GridMap]. - [param body_shape_index] the index of the [Shape3D] of the [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code]. - [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code]. + Emitted when a [Shape3D] of the received [param body] enters a shape of this area. [param body] can be a [PhysicsBody3D] or a [GridMap]. [GridMap]s are detected if their [MeshLibrary] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code]. + [param local_shape_index] and [param body_shape_index] contain indices of the interacting shapes from this area and the interacting body, respectively. [param body_rid] contains the [RID] of the body. These values can be used with the [PhysicsServer3D]. + [b]Example of getting the[/b] [CollisionShape3D] [b]node from the shape index:[/b] + [codeblocks] + [gdscript] + var body_shape_owner = body.shape_find_owner(body_shape_index) + var body_shape_node = body.shape_owner_get_owner(body_shape_owner) + + var local_shape_owner = shape_find_owner(local_shape_index) + var local_shape_node = shape_owner_get_owner(local_shape_owner) + [/gdscript] + [/codeblocks] </description> </signal> <signal name="body_shape_exited"> @@ -203,11 +210,8 @@ <param index="2" name="body_shape_index" type="int" /> <param index="3" name="local_shape_index" type="int" /> <description> - Emitted when one of a [PhysicsBody3D] or [GridMap]'s [Shape3D]s enters one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s. - [param body_rid] the [RID] of the [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D]. - [param body] the [Node], if it exists in the tree, of the [PhysicsBody3D] or [GridMap]. - [param body_shape_index] the index of the [Shape3D] of the [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code]. - [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code]. + Emitted when a [Shape3D] of the received [param body] exits a shape of this area. [param body] can be a [PhysicsBody3D] or a [GridMap]. [GridMap]s are detected if their [MeshLibrary] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code]. + See also [signal body_shape_entered]. </description> </signal> </signals> diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml index b9c8ab0f6c..70ce4ad516 100644 --- a/doc/classes/ArrayMesh.xml +++ b/doc/classes/ArrayMesh.xml @@ -102,13 +102,13 @@ <param index="0" name="transform" type="Transform3D" /> <param index="1" name="texel_size" type="float" /> <description> - Will perform a UV unwrap on the [ArrayMesh] to prepare the mesh for lightmapping. + Performs a UV unwrap on the [ArrayMesh] to prepare the mesh for lightmapping. </description> </method> <method name="regen_normal_maps"> <return type="void" /> <description> - Will regenerate normal maps for the [ArrayMesh]. + Regenerates tangents for each of the [ArrayMesh]'s surfaces. </description> </method> <method name="set_blend_shape_name"> diff --git a/doc/classes/AudioStreamRandomizer.xml b/doc/classes/AudioStreamRandomizer.xml index 9b58d78af5..d93f853c89 100644 --- a/doc/classes/AudioStreamRandomizer.xml +++ b/doc/classes/AudioStreamRandomizer.xml @@ -12,8 +12,10 @@ <method name="add_stream"> <return type="void" /> <param index="0" name="index" type="int" /> + <param index="1" name="stream" type="AudioStream" /> + <param index="2" name="weight" type="float" default="1.0" /> <description> - Insert a stream at the specified index. + Insert a stream at the specified index. If the index is less than zero, the insertion occurs at the end of the underlying pool. </description> </method> <method name="get_stream" qualifiers="const"> diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml index d2c9a77486..961f3c495a 100644 --- a/doc/classes/Button.xml +++ b/doc/classes/Button.xml @@ -118,6 +118,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> [Font] of the [Button]'s text. diff --git a/doc/classes/ButtonGroup.xml b/doc/classes/ButtonGroup.xml index 277bda2836..8195669b10 100644 --- a/doc/classes/ButtonGroup.xml +++ b/doc/classes/ButtonGroup.xml @@ -4,8 +4,8 @@ Group of Buttons. </brief_description> <description> - Group of [Button]. All direct and indirect children buttons become radios. Only one allows being pressed. - [member BaseButton.toggle_mode] should be [code]true[/code]. + Group of [BaseButton]. The members of this group are treated like radio buttons in the sense that only one button can be pressed at the same time. + Every member of the ButtonGroup should have [member BaseButton.toggle_mode] set to [code]true[/code]. </description> <tutorials> </tutorials> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 499d53e63c..5171e0acbe 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -153,6 +153,7 @@ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" /> <param index="4" name="outline" type="float" default="0.0" /> <param index="5" name="pixel_range" type="float" default="4.0" /> + <param index="6" name="scale" type="float" default="1.0" /> <description> Draws a textured rectangle region of the multi-channel signed distance field texture at a given position, optionally modulated by a color. See [member FontFile.multichannel_signed_distance_field] for more information and caveats about MSDF font rendering. If [param outline] is positive, each alpha channel value of pixel in region is set to maximum value of true distance in the [param outline] radius. @@ -404,7 +405,7 @@ <method name="get_canvas_transform" qualifiers="const"> <return type="Transform2D" /> <description> - Returns the transform matrix of this item's canvas. + Returns the transform from the coordinate system of the canvas, this item is in, to the [Viewport]s coordinate system. </description> </method> <method name="get_global_mouse_position" qualifiers="const"> @@ -422,7 +423,7 @@ <method name="get_global_transform_with_canvas" qualifiers="const"> <return type="Transform2D" /> <description> - Returns the global transform matrix of this item in relation to the canvas. + Returns the transform from the local coordinate system of this [CanvasItem] to the [Viewport]s coordinate system. </description> </method> <method name="get_local_mouse_position" qualifiers="const"> @@ -453,7 +454,7 @@ <method name="get_viewport_transform" qualifiers="const"> <return type="Transform2D" /> <description> - Returns this item's transform in relation to the viewport. + Returns the transform from the coordinate system of the canvas, this item is in, to the [Viewport]s embedders coordinate system. </description> </method> <method name="get_visibility_layer_bit" qualifiers="const"> diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml index 7c1b19b961..ce999c06d3 100644 --- a/doc/classes/CanvasLayer.xml +++ b/doc/classes/CanvasLayer.xml @@ -19,6 +19,12 @@ Returns the RID of the canvas used by this layer. </description> </method> + <method name="get_final_transform" qualifiers="const"> + <return type="Transform2D" /> + <description> + Returns the transform from the [CanvasLayer]s coordinate system to the [Viewport]s coordinate system. + </description> + </method> <method name="hide"> <return type="void" /> <description> diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml index 699e872e99..3ee18cf351 100644 --- a/doc/classes/CheckBox.xml +++ b/doc/classes/CheckBox.xml @@ -43,6 +43,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> The [Font] to use for the [CheckBox] text. diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml index dfbaa7cbee..03578cafd0 100644 --- a/doc/classes/CheckButton.xml +++ b/doc/classes/CheckButton.xml @@ -43,6 +43,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> The [Font] to use for the [CheckButton] text. diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml index e7ef5fb289..c313e6c875 100644 --- a/doc/classes/CodeEdit.xml +++ b/doc/classes/CodeEdit.xml @@ -651,6 +651,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> Sets the default [Font]. diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index 2b287d7546..823433c2df 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ColorPicker" inherits="BoxContainer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="ColorPicker" inherits="VBoxContainer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Color picker control. </brief_description> @@ -88,7 +88,6 @@ <member name="sliders_visible" type="bool" setter="set_sliders_visible" getter="are_sliders_visible" default="true"> If [code]true[/code], the color sliders are visible. </member> - <member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" overrides="BoxContainer" default="true" /> </members> <signals> <signal name="color_changed"> diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml index b7a0bdfb0c..2a37cc162a 100644 --- a/doc/classes/ColorPickerButton.xml +++ b/doc/classes/ColorPickerButton.xml @@ -79,6 +79,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> [Font] of the [ColorPickerButton]'s text. diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index fd6aab6a49..b0351559ee 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -1050,6 +1050,9 @@ <member name="rotation" type="float" setter="set_rotation" getter="get_rotation" default="0.0"> The node's rotation around its pivot, in radians. See [member pivot_offset] to change the pivot's position. </member> + <member name="rotation_degrees" type="float" setter="set_rotation_degrees" getter="get_rotation_degrees"> + Helper property to access [member rotation] in degrees instead of radians. + </member> <member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2(1, 1)"> The node's scale, relative to its [member size]. Change this property to scale the node around its [member pivot_offset]. The Control's [member tooltip_text] will also scale according to this value. [b]Note:[/b] This property is mainly intended to be used for animation purposes. Text inside the Control will look pixelated or blurry when the Control is scaled. To support multiple resolutions in your project, use an appropriate viewport stretch mode as described in the [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]documentation[/url] instead of scaling Controls individually. diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml index de105b32e1..d270d32df7 100644 --- a/doc/classes/EditorSpinSlider.xml +++ b/doc/classes/EditorSpinSlider.xml @@ -28,4 +28,26 @@ The suffix to display after the value (in a faded color). This should generally be a plural word. You may have to use an abbreviation if the suffix is too long to be displayed. </member> </members> + <signals> + <signal name="grabbed"> + <description> + Emitted when the spinner/slider is grabbed. + </description> + </signal> + <signal name="ungrabbed"> + <description> + Emitted when the spinner/slider is ungrabbed. + </description> + </signal> + <signal name="value_focus_entered"> + <description> + Emitted when the value form gains focus. + </description> + </signal> + <signal name="value_focus_exited"> + <description> + Emitted when the value form loses focus. + </description> + </signal> + </signals> </class> diff --git a/doc/classes/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml index b766978c04..85c10fefd9 100644 --- a/doc/classes/EditorVCSInterface.xml +++ b/doc/classes/EditorVCSInterface.xml @@ -53,7 +53,7 @@ </description> </method> <method name="_get_branch_list" qualifiers="virtual"> - <return type="Dictionary[]" /> + <return type="String[]" /> <description> Gets an instance of an [Array] of [String]s containing available branch names in the VCS. </description> @@ -94,7 +94,7 @@ </description> </method> <method name="_get_remotes" qualifiers="virtual"> - <return type="Dictionary[]" /> + <return type="String[]" /> <description> Returns an [Array] of [String]s, each containing the name of a remote configured in the VCS. </description> diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml index 1019c271dc..69a7627774 100644 --- a/doc/classes/FontFile.xml +++ b/doc/classes/FontFile.xml @@ -570,7 +570,7 @@ Weight (boldness) of the font. A value in the [code]100...999[/code] range, normal font weight is [code]400[/code], bold font weight is [code]700[/code]. </member> <member name="force_autohinter" type="bool" setter="set_force_autohinter" getter="is_force_autohinter" default="false"> - If set to [code]true[/code], auto-hinting is supported and preferred over font built-in hinting. Used by dynamic fonts only. + If set to [code]true[/code], auto-hinting is supported and preferred over font built-in hinting. Used by dynamic fonts only (MSDF fonts don't support hinting). </member> <member name="generate_mipmaps" type="bool" setter="set_generate_mipmaps" getter="get_generate_mipmaps" default="false"> If set to [code]true[/code], generate mipmaps for the font textures. @@ -579,25 +579,27 @@ Font hinting mode. Used by dynamic fonts only. </member> <member name="msdf_pixel_range" type="int" setter="set_msdf_pixel_range" getter="get_msdf_pixel_range" default="16"> - The width of the range around the shape between the minimum and maximum representable signed distance. + The width of the range around the shape between the minimum and maximum representable signed distance. If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline. The default [member msdf_pixel_range] value of [code]16[/code] allows outline sizes up to [code]8[/code] to look correct. </member> <member name="msdf_size" type="int" setter="set_msdf_size" getter="get_msdf_size" default="48"> - Source font size used to generate MSDF textures. + Source font size used to generate MSDF textures. Higher values allow for more precision, but are slower to render and require more memory. Only increase this value if you notice a visible lack of precision in glyph rendering. </member> <member name="multichannel_signed_distance_field" type="bool" setter="set_multichannel_signed_distance_field" getter="is_multichannel_signed_distance_field" default="false"> - If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data. + If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field (MSDF) generated from the dynamic font vector data. Since this approach does not rely on rasterizing the font every time its size changes, this allows for resizing the font in real-time without any performance penalty. Text will also not look grainy for [Control]s that are scaled down (or for [Label3D]s viewed from a long distance). As a downside, font hinting is not available with MSDF. The lack of font hinting may result in less crisp and less readable fonts at small sizes. + [b]Note:[/b] If using font outlines, [member msdf_pixel_range] must be set to at least [i]twice[/i] the size of the largest font outline. + [b]Note:[/b] MSDF font rendering does not render glyphs with overlapping shapes correctly. Overlapping shapes are not valid per the OpenType standard, but are still commonly found in many font files, especially those converted by Google Fonts. To avoid issues with overlapping glyphs, consider downloading the font file directly from the type foundry instead of relying on Google Fonts. </member> <member name="opentype_feature_overrides" type="Dictionary" setter="set_opentype_feature_overrides" getter="get_opentype_feature_overrides" default="{}"> Font OpenType feature set override. </member> <member name="oversampling" type="float" setter="set_oversampling" getter="get_oversampling" default="0.0"> - Font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only. + Font oversampling factor. If set to [code]0.0[/code], the global oversampling factor is used instead. Used by dynamic fonts only (MSDF fonts ignore oversampling). </member> <member name="style_name" type="String" setter="set_font_style_name" getter="get_font_style_name" default=""""> Font style name. </member> <member name="subpixel_positioning" type="int" setter="set_subpixel_positioning" getter="get_subpixel_positioning" enum="TextServer.SubpixelPositioning" default="1"> - Font glyph subpixel positioning mode. Subpixel positioning provides shaper text and better kerning for smaller font sizes, at the cost of memory usage and font rasterization speed. Use [constant TextServer.SUBPIXEL_POSITIONING_AUTO] to automatically enable it based on the font size. + Font glyph subpixel positioning mode. Subpixel positioning provides shaper text and better kerning for smaller font sizes, at the cost of higher memory usage and lower font rasterization speed. Use [constant TextServer.SUBPIXEL_POSITIONING_AUTO] to automatically enable it based on the font size. </member> </members> </class> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index be66b8a7b9..ed1b40488e 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -76,8 +76,12 @@ <param index="0" name="mode" type="int" enum="Image.CompressMode" /> <param index="1" name="source" type="int" enum="Image.CompressSource" default="0" /> <param index="2" name="lossy_quality" type="float" default="0.7" /> + <param index="3" name="astc_format" type="int" enum="Image.ASTCFormat" default="0" /> <description> - Compresses the image to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available. See [enum CompressMode] and [enum CompressSource] constants. + Compresses the image to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available. + The [param mode] parameter helps to pick the best compression method for DXT and ETC2 formats. It is ignored for ASTC compression. + The [param lossy_quality] parameter is optional for compressors that support it. + For ASTC compression, the [param astc_format] parameter must be supplied. </description> </method> <method name="compress_from_channels"> @@ -85,7 +89,12 @@ <param index="0" name="mode" type="int" enum="Image.CompressMode" /> <param index="1" name="channels" type="int" enum="Image.UsedChannels" /> <param index="2" name="lossy_quality" type="float" default="0.7" /> + <param index="3" name="astc_format" type="int" enum="Image.ASTCFormat" default="0" /> <description> + Compresses the image to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available. + This is an alternative to [method compress] that lets the user supply the channels used in order for the compressor to pick the best DXT and ETC2 formats. For other formats (non DXT or ETC2), this argument is ignored. + The [param lossy_quality] parameter is optional for compressors that support it. + For ASTC compression, the [param astc_format] parameter must be supplied. </description> </method> <method name="compute_image_metrics"> @@ -658,7 +667,19 @@ </constant> <constant name="FORMAT_DXT5_RA_AS_RG" value="34" enum="Format"> </constant> - <constant name="FORMAT_MAX" value="35" enum="Format"> + <constant name="FORMAT_ASTC_4x4" value="35" enum="Format"> + [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texutre Compression[/url]. This implements the 4x4 (high quality) mode. + </constant> + <constant name="FORMAT_ASTC_4x4_HDR" value="36" enum="Format"> + Same format as [constant FORMAT_ASTC_4x4], but with the hint to let the GPU know it is used for HDR. + </constant> + <constant name="FORMAT_ASTC_8x8" value="37" enum="Format"> + [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texutre Compression[/url]. This implements the 8x8 (low quality) mode. + </constant> + <constant name="FORMAT_ASTC_8x8_HDR" value="38" enum="Format"> + Same format as [constant FORMAT_ASTC_8x8], but with the hint to let the GPU know it is used for HDR. + </constant> + <constant name="FORMAT_MAX" value="39" enum="Format"> Represents the size of the [enum Format] enum. </constant> <constant name="INTERPOLATE_NEAREST" value="0" enum="Interpolation"> @@ -722,5 +743,11 @@ <constant name="COMPRESS_SOURCE_NORMAL" value="2" enum="CompressSource"> Source texture (before compression) is a normal texture (e.g. it can be compressed into two channels). </constant> + <constant name="ASTC_FORMAT_4x4" value="0" enum="ASTCFormat"> + Hint to indicate that the high quality 4x4 ASTC compression format should be used. + </constant> + <constant name="ASTC_FORMAT_8x8" value="1" enum="ASTCFormat"> + Hint to indicate that the low quality 8x8 ASTC compression format should be used. + </constant> </constants> </class> diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml index 844f260971..c485d26e0c 100644 --- a/doc/classes/ItemList.xml +++ b/doc/classes/ItemList.xml @@ -459,6 +459,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the item text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="v_separation" data_type="constant" type="int" default="2"> The vertical spacing between items. diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml index cd87b4558f..1a8cbf0584 100644 --- a/doc/classes/Label.xml +++ b/doc/classes/Label.xml @@ -111,6 +111,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> Text outline size. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="shadow_offset_x" data_type="constant" type="int" default="1"> The horizontal offset of the text's shadow. diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index e57cc68b36..b8383aaed9 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -424,6 +424,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> Font used for the text. diff --git a/doc/classes/LinkButton.xml b/doc/classes/LinkButton.xml index d7701ea184..b3938999f3 100644 --- a/doc/classes/LinkButton.xml +++ b/doc/classes/LinkButton.xml @@ -28,7 +28,23 @@ Base text writing direction. </member> <member name="underline" type="int" setter="set_underline_mode" getter="get_underline_mode" enum="LinkButton.UnderlineMode" default="0"> - Determines when to show the underline. See [enum UnderlineMode] for options. + The underline mode to use for the text. See [enum LinkButton.UnderlineMode] for the available modes. + </member> + <member name="uri" type="String" setter="set_uri" getter="get_uri" default=""""> + The [url=https://en.wikipedia.org/wiki/Uniform_Resource_Identifier]URI[/url] for this [LinkButton]. If set to a valid URI, pressing the button opens the URI using the operating system's default program for the protocol (via [method OS.shell_open]). HTTP and HTTPS URLs open the default web browser. + [b]Examples:[/b] + [codeblocks] + [gdscript] + uri = "https://godotengine.org" # Opens the URL in the default web browser. + uri = "C:\SomeFolder" # Opens the file explorer at the given path. + uri = "C:\SomeImage.png" # Opens the given image in the default viewing app. + [/gdscript] + [csharp] + Uri = "https://godotengine.org"; // Opens the URL in the default web browser. + Uri = "C:\SomeFolder"; // Opens the file explorer at the given path. + Uri = "C:\SomeImage.png"; // Opens the given image in the default viewing app. + [/csharp] + [/codeblocks] </member> </members> <constants> @@ -60,6 +76,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="underline_spacing" data_type="constant" type="int" default="2"> The vertical space between the baseline of text and the underline. diff --git a/doc/classes/MenuBar.xml b/doc/classes/MenuBar.xml index e8505937ff..79876e56a3 100644 --- a/doc/classes/MenuBar.xml +++ b/doc/classes/MenuBar.xml @@ -143,6 +143,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> [Font] of the menu item's text. diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml index 4d5d5a011b..3061149570 100644 --- a/doc/classes/MenuButton.xml +++ b/doc/classes/MenuButton.xml @@ -75,6 +75,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> [Font] of the [MenuButton]'s text. diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml index 85e57dd0f3..7c93ba5dce 100644 --- a/doc/classes/MeshLibrary.xml +++ b/doc/classes/MeshLibrary.xml @@ -59,14 +59,21 @@ Returns the item's name. </description> </method> - <method name="get_item_navmesh" qualifiers="const"> + <method name="get_item_navigation_layers" qualifiers="const"> + <return type="int" /> + <param index="0" name="id" type="int" /> + <description> + Returns the item's navigation layers bitmask. + </description> + </method> + <method name="get_item_navigation_mesh" qualifiers="const"> <return type="NavigationMesh" /> <param index="0" name="id" type="int" /> <description> Returns the item's navigation mesh. </description> </method> - <method name="get_item_navmesh_transform" qualifiers="const"> + <method name="get_item_navigation_mesh_transform" qualifiers="const"> <return type="Transform3D" /> <param index="0" name="id" type="int" /> <description> @@ -126,18 +133,26 @@ This name is shown in the editor. It can also be used to look up the item later using [method find_item_by_name]. </description> </method> - <method name="set_item_navmesh"> + <method name="set_item_navigation_layers"> + <return type="void" /> + <param index="0" name="id" type="int" /> + <param index="1" name="navigation_layers" type="int" /> + <description> + Sets the item's navigation layers bitmask. + </description> + </method> + <method name="set_item_navigation_mesh"> <return type="void" /> <param index="0" name="id" type="int" /> - <param index="1" name="navmesh" type="NavigationMesh" /> + <param index="1" name="navigation_mesh" type="NavigationMesh" /> <description> Sets the item's navigation mesh. </description> </method> - <method name="set_item_navmesh_transform"> + <method name="set_item_navigation_mesh_transform"> <return type="void" /> <param index="0" name="id" type="int" /> - <param index="1" name="navmesh" type="Transform3D" /> + <param index="1" name="navigation_mesh" type="Transform3D" /> <description> Sets the transform to apply to the item's navigation mesh. </description> diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml index 8cf7824ff7..31d347d76c 100644 --- a/doc/classes/NavigationAgent2D.xml +++ b/doc/classes/NavigationAgent2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationAgent2D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationAgent2D" inherits="Node" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> 2D Agent used in navigation for collision avoidance. </brief_description> @@ -16,24 +16,30 @@ Returns the distance to the target location, using the agent's global position. The user must set [member target_location] in order for this to be accurate. </description> </method> - <method name="get_final_location"> - <return type="Vector2" /> - <description> - Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame. - </description> - </method> - <method name="get_nav_path" qualifiers="const"> + <method name="get_current_navigation_path" qualifiers="const"> <return type="PackedVector2Array" /> <description> Returns this agent's current path from start to finish in global coordinates. The path only updates when the target location is changed or the agent requires a repath. The path array is not intended to be used in direct path movement as the agent has its own internal path logic that would get corrupted by changing the path array manually. Use the intended [method get_next_location] once every physics frame to receive the next path point for the agents movement as this function also updates the internal path logic. </description> </method> - <method name="get_nav_path_index" qualifiers="const"> + <method name="get_current_navigation_path_index" qualifiers="const"> <return type="int" /> <description> Returns which index the agent is currently on in the navigation path's [PackedVector2Array]. </description> </method> + <method name="get_current_navigation_result" qualifiers="const"> + <return type="NavigationPathQueryResult2D" /> + <description> + Returns the path query result for the path the agent is currently following. + </description> + </method> + <method name="get_final_location"> + <return type="Vector2" /> + <description> + Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame. + </description> + </method> <method name="get_navigation_layer_value" qualifiers="const"> <return type="bool" /> <param index="0" name="layer_number" type="int" /> @@ -122,6 +128,9 @@ <member name="path_max_distance" type="float" setter="set_path_max_distance" getter="get_path_max_distance" default="3.0"> The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path. </member> + <member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters2D.PathMetadataFlags" default="7"> + Additional information to return with the navigation path. + </member> <member name="radius" type="float" setter="set_radius" getter="get_radius" default="10.0"> The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]). Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size. @@ -137,6 +146,17 @@ </member> </members> <signals> + <signal name="link_reached"> + <param index="0" name="details" type="Dictionary" /> + <description> + Notifies when a navigation link has been reached. + The details dictionary may contain the following keys depending on the value of [member path_metadata_flags]: + - [code]location[/code]: The start location of the link that was reached. + - [code]type[/code]: Always [constant NavigationPathQueryResult2D.PATH_SEGMENT_TYPE_LINK]. + - [code]rid[/code]: The [RID] of the link. + - [code]owner[/code]: The object which manages the link (usually [NavigationLink2D]). + </description> + </signal> <signal name="navigation_finished"> <description> Notifies when the final location is reached. @@ -158,5 +178,16 @@ Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity]. Only emitted when [member avoidance_enabled] is true. </description> </signal> + <signal name="waypoint_reached"> + <param index="0" name="details" type="Dictionary" /> + <description> + Notifies when a waypoint along the path has been reached. + The details dictionary may contain the following keys depending on the value of [member path_metadata_flags]: + - [code]location[/code]: The location of the waypoint that was reached. + - [code]type[/code]: The type of navigation primitive (region or link) that contains this waypoint. + - [code]rid[/code]: The [RID] of the containing navigation primitive (region or link). + - [code]owner[/code]: The object which manages the containing navigation primitive (region or link). + </description> + </signal> </signals> </class> diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml index 44c17647f7..c3f4809b5e 100644 --- a/doc/classes/NavigationAgent3D.xml +++ b/doc/classes/NavigationAgent3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationAgent3D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationAgent3D" inherits="Node" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> 3D Agent used in navigation for collision avoidance. </brief_description> @@ -16,24 +16,30 @@ Returns the distance to the target location, using the agent's global position. The user must set [member target_location] in order for this to be accurate. </description> </method> - <method name="get_final_location"> - <return type="Vector3" /> - <description> - Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame. - </description> - </method> - <method name="get_nav_path" qualifiers="const"> + <method name="get_current_navigation_path" qualifiers="const"> <return type="PackedVector3Array" /> <description> Returns this agent's current path from start to finish in global coordinates. The path only updates when the target location is changed or the agent requires a repath. The path array is not intended to be used in direct path movement as the agent has its own internal path logic that would get corrupted by changing the path array manually. Use the intended [method get_next_location] once every physics frame to receive the next path point for the agents movement as this function also updates the internal path logic. </description> </method> - <method name="get_nav_path_index" qualifiers="const"> + <method name="get_current_navigation_path_index" qualifiers="const"> <return type="int" /> <description> Returns which index the agent is currently on in the navigation path's [PackedVector3Array]. </description> </method> + <method name="get_current_navigation_result" qualifiers="const"> + <return type="NavigationPathQueryResult3D" /> + <description> + Returns the path query result for the path the agent is currently following. + </description> + </method> + <method name="get_final_location"> + <return type="Vector3" /> + <description> + Returns the reachable final location in global coordinates. This can change if the navigation path is altered in any way. Because of this, it would be best to check this each frame. + </description> + </method> <method name="get_navigation_layer_value" qualifiers="const"> <return type="bool" /> <param index="0" name="layer_number" type="int" /> @@ -128,6 +134,9 @@ <member name="path_max_distance" type="float" setter="set_path_max_distance" getter="get_path_max_distance" default="3.0"> The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path. </member> + <member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters3D.PathMetadataFlags" default="7"> + Additional information to return with the navigation path. + </member> <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0"> The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]). Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size. @@ -143,6 +152,17 @@ </member> </members> <signals> + <signal name="link_reached"> + <param index="0" name="details" type="Dictionary" /> + <description> + Notifies when a navigation link has been reached. + The details dictionary may contain the following keys depending on the value of [member path_metadata_flags]: + - [code]location[/code]: The start location of the link that was reached. + - [code]type[/code]: Always [constant NavigationPathQueryResult3D.PATH_SEGMENT_TYPE_LINK]. + - [code]rid[/code]: The [RID] of the link. + - [code]owner[/code]: The object which manages the link (usually [NavigationLink3D]). + </description> + </signal> <signal name="navigation_finished"> <description> Notifies when the final location is reached. @@ -164,5 +184,16 @@ Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity]. Only emitted when [member avoidance_enabled] is true. </description> </signal> + <signal name="waypoint_reached"> + <param index="0" name="details" type="Dictionary" /> + <description> + Notifies when a waypoint along the path has been reached. + The details dictionary may contain the following keys depending on the value of [member path_metadata_flags]: + - [code]location[/code]: The location of the waypoint that was reached. + - [code]type[/code]: The type of navigation primitive (region or link) that contains this waypoint. + - [code]rid[/code]: The [RID] of the containing navigation primitive (region or link). + - [code]owner[/code]: The object which manages the containing navigation primitive (region or link). + </description> + </signal> </signals> </class> diff --git a/doc/classes/NavigationLink2D.xml b/doc/classes/NavigationLink2D.xml index 1e086fb730..9d75694360 100644 --- a/doc/classes/NavigationLink2D.xml +++ b/doc/classes/NavigationLink2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationLink2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationLink2D" inherits="Node2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Creates a link between two locations that [NavigationServer2D] can route agents through. </brief_description> @@ -38,7 +38,7 @@ The distance the link will search is controlled by [method NavigationServer2D.map_set_link_connection_radius]. </member> <member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0"> - When pathfinding enters this link from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path. + When pathfinding enters this link from another regions navigation mesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path. </member> <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> A bitfield determining all navigation layers the link belongs to. These navigation layers will be checked when requesting a path with [method NavigationServer2D.map_get_path]. diff --git a/doc/classes/NavigationLink3D.xml b/doc/classes/NavigationLink3D.xml index 4d5d81bec5..730c43c5a8 100644 --- a/doc/classes/NavigationLink3D.xml +++ b/doc/classes/NavigationLink3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationLink3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationLink3D" inherits="Node3D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Creates a link between two locations that [NavigationServer3D] can route agents through. </brief_description> @@ -38,7 +38,7 @@ The distance the link will search is controlled by [method NavigationServer3D.map_set_link_connection_radius]. </member> <member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0"> - When pathfinding enters this link from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path. + When pathfinding enters this link from another regions navigation mesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path. </member> <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> A bitfield determining all navigation layers the link belongs to. These navigation layers will be checked when requesting a path with [method NavigationServer3D.map_get_path]. diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml index c86bc47e04..ff898551d4 100644 --- a/doc/classes/NavigationMesh.xml +++ b/doc/classes/NavigationMesh.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationMesh" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationMesh" inherits="Resource" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A mesh to approximate the walkable areas and obstacles. </brief_description> @@ -133,13 +133,10 @@ <member name="geometry_source_geometry_mode" type="int" setter="set_source_geometry_mode" getter="get_source_geometry_mode" enum="NavigationMesh.SourceGeometryMode" default="0"> The source of the geometry used when baking. See [enum SourceGeometryMode] for possible values. </member> - <member name="geometry_source_group_name" type="StringName" setter="set_source_group_name" getter="get_source_group_name" default="&"navmesh""> + <member name="geometry_source_group_name" type="StringName" setter="set_source_group_name" getter="get_source_group_name" default="&"navigation_mesh_source_group""> The name of the group to scan for geometry. Only used when [member geometry_source_geometry_mode] is [constant SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN] or [constant SOURCE_GEOMETRY_GROUPS_EXPLICIT]. </member> - <member name="polygon_verts_per_poly" type="float" setter="set_verts_per_poly" getter="get_verts_per_poly" default="6.0"> - The maximum number of vertices allowed for polygons generated during the contour to polygon conversion process. - </member> <member name="region_merge_size" type="float" setter="set_region_merge_size" getter="get_region_merge_size" default="20.0"> Any regions with a size smaller than this will be merged with larger regions if possible. [b]Note:[/b] This value will be squared to calculate the number of cells. For example, a value of 20 will set the number of cells to 400. @@ -151,6 +148,9 @@ <member name="sample_partition_type" type="int" setter="set_sample_partition_type" getter="get_sample_partition_type" enum="NavigationMesh.SamplePartitionType" default="0"> Partitioning algorithm for creating the navigation mesh polys. See [enum SamplePartitionType] for possible values. </member> + <member name="vertices_per_polygon" type="float" setter="set_vertices_per_polygon" getter="get_vertices_per_polygon" default="6.0"> + The maximum number of vertices allowed for polygons generated during the contour to polygon conversion process. + </member> </members> <constants> <constant name="SAMPLE_PARTITION_WATERSHED" value="0" enum="SamplePartitionType"> @@ -177,8 +177,8 @@ <constant name="PARSED_GEOMETRY_MAX" value="3" enum="ParsedGeometryType"> Represents the size of the [enum ParsedGeometryType] enum. </constant> - <constant name="SOURCE_GEOMETRY_NAVMESH_CHILDREN" value="0" enum="SourceGeometryMode"> - Scans the child nodes of [NavigationRegion3D] recursively for geometry. + <constant name="SOURCE_GEOMETRY_ROOT_NODE_CHILDREN" value="0" enum="SourceGeometryMode"> + Scans the child nodes of the root node recursively for geometry. </constant> <constant name="SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN" value="1" enum="SourceGeometryMode"> Scans nodes in a group and their child nodes recursively for geometry. The group is specified by [member geometry_source_group_name]. diff --git a/doc/classes/NavigationMeshGenerator.xml b/doc/classes/NavigationMeshGenerator.xml index 4c337db90f..15d149a229 100644 --- a/doc/classes/NavigationMeshGenerator.xml +++ b/doc/classes/NavigationMeshGenerator.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationMeshGenerator" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationMeshGenerator" inherits="Object" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Helper class for creating and clearing navigation meshes. </brief_description> @@ -15,17 +15,17 @@ <methods> <method name="bake"> <return type="void" /> - <param index="0" name="nav_mesh" type="NavigationMesh" /> + <param index="0" name="navigation_mesh" type="NavigationMesh" /> <param index="1" name="root_node" type="Node" /> <description> - Bakes navigation data to the provided [param nav_mesh] by parsing child nodes under the provided [param root_node] or a specific group of nodes for potential source geometry. The parse behavior can be controlled with the [member NavigationMesh.geometry_parsed_geometry_type] and [member NavigationMesh.geometry_source_geometry_mode] properties on the [NavigationMesh] resource. + Bakes navigation data to the provided [param navigation_mesh] by parsing child nodes under the provided [param root_node] or a specific group of nodes for potential source geometry. The parse behavior can be controlled with the [member NavigationMesh.geometry_parsed_geometry_type] and [member NavigationMesh.geometry_source_geometry_mode] properties on the [NavigationMesh] resource. </description> </method> <method name="clear"> <return type="void" /> - <param index="0" name="nav_mesh" type="NavigationMesh" /> + <param index="0" name="navigation_mesh" type="NavigationMesh" /> <description> - Removes all polygons and vertices from the provided [param nav_mesh] resource. + Removes all polygons and vertices from the provided [param navigation_mesh] resource. </description> </method> </methods> diff --git a/doc/classes/NavigationObstacle2D.xml b/doc/classes/NavigationObstacle2D.xml index 68d9691ccf..ce0f05ad28 100644 --- a/doc/classes/NavigationObstacle2D.xml +++ b/doc/classes/NavigationObstacle2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationObstacle2D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationObstacle2D" inherits="Node" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> 2D Obstacle used in navigation for collision avoidance. </brief_description> diff --git a/doc/classes/NavigationObstacle3D.xml b/doc/classes/NavigationObstacle3D.xml index 90eb55887f..78bbb788d9 100644 --- a/doc/classes/NavigationObstacle3D.xml +++ b/doc/classes/NavigationObstacle3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationObstacle3D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationObstacle3D" inherits="Node" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> 3D Obstacle used in navigation for collision avoidance. </brief_description> diff --git a/doc/classes/NavigationPathQueryParameters2D.xml b/doc/classes/NavigationPathQueryParameters2D.xml index 397ca8b713..511b2e7a8c 100644 --- a/doc/classes/NavigationPathQueryParameters2D.xml +++ b/doc/classes/NavigationPathQueryParameters2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationPathQueryParameters2D" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationPathQueryParameters2D" inherits="RefCounted" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Parameters to be sent to a 2D navigation path query. </brief_description> @@ -12,6 +12,9 @@ <member name="map" type="RID" setter="set_map" getter="get_map"> The navigation [code]map[/code] [RID] used in the path query. </member> + <member name="metadata_flags" type="int" setter="set_metadata_flags" getter="get_metadata_flags" enum="NavigationPathQueryParameters2D.PathMetadataFlags" default="7"> + Additional information to include with the navigation path. + </member> <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> The navigation layers the query will use (as a bitmask). </member> @@ -33,10 +36,25 @@ The path query uses the default A* pathfinding algorithm. </constant> <constant name="PATH_POSTPROCESSING_CORRIDORFUNNEL" value="0" enum="PathPostProcessing"> - Applies a funnel algorithm to the raw path corridor found by the pathfinding algorithm. This will result in the shortest path possible inside the path corridor. This postprocessing very much depends on the navmesh polygon layout and the created corridor. Especially tile- or gridbased layouts can face artificial corners with diagonal movement due to a jagged path corridor imposed by the cell shapes. + Applies a funnel algorithm to the raw path corridor found by the pathfinding algorithm. This will result in the shortest path possible inside the path corridor. This postprocessing very much depends on the navigation mesh polygon layout and the created corridor. Especially tile- or gridbased layouts can face artificial corners with diagonal movement due to a jagged path corridor imposed by the cell shapes. </constant> <constant name="PATH_POSTPROCESSING_EDGECENTERED" value="1" enum="PathPostProcessing"> - Centers every path position in the middle of the traveled navmesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center. + Centers every path position in the middle of the traveled navigation mesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center. + </constant> + <constant name="PATH_METADATA_INCLUDE_NONE" value="0" enum="PathMetadataFlags" is_bitfield="true"> + Don't include any additional metadata about the returned path. + </constant> + <constant name="PATH_METADATA_INCLUDE_TYPES" value="1" enum="PathMetadataFlags" is_bitfield="true"> + Include the type of navigation primitive (region or link) that each point of the path goes through. + </constant> + <constant name="PATH_METADATA_INCLUDE_RIDS" value="2" enum="PathMetadataFlags" is_bitfield="true"> + Include the [RID]s of the regions and links that each point of the path goes through. + </constant> + <constant name="PATH_METADATA_INCLUDE_OWNERS" value="4" enum="PathMetadataFlags" is_bitfield="true"> + Include the [code]ObjectID[/code]s of the [Object]s which manage the regions and links each point of the path goes through. + </constant> + <constant name="PATH_METADATA_INCLUDE_ALL" value="7" enum="PathMetadataFlags" is_bitfield="true"> + Include all available metadata about the returned path. </constant> </constants> </class> diff --git a/doc/classes/NavigationPathQueryParameters3D.xml b/doc/classes/NavigationPathQueryParameters3D.xml index 29faa5561b..b5031f60f2 100644 --- a/doc/classes/NavigationPathQueryParameters3D.xml +++ b/doc/classes/NavigationPathQueryParameters3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationPathQueryParameters3D" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationPathQueryParameters3D" inherits="RefCounted" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Parameters to be sent to a 3D navigation path query. </brief_description> @@ -12,6 +12,9 @@ <member name="map" type="RID" setter="set_map" getter="get_map"> The navigation [code]map[/code] [RID] used in the path query. </member> + <member name="metadata_flags" type="int" setter="set_metadata_flags" getter="get_metadata_flags" enum="NavigationPathQueryParameters3D.PathMetadataFlags" default="7"> + Additional information to include with the navigation path. + </member> <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> The navigation layers the query will use (as a bitmask). </member> @@ -33,10 +36,25 @@ The path query uses the default A* pathfinding algorithm. </constant> <constant name="PATH_POSTPROCESSING_CORRIDORFUNNEL" value="0" enum="PathPostProcessing"> - Applies a funnel algorithm to the raw path corridor found by the pathfinding algorithm. This will result in the shortest path possible inside the path corridor. This postprocessing very much depends on the navmesh polygon layout and the created corridor. Especially tile- or gridbased layouts can face artificial corners with diagonal movement due to a jagged path corridor imposed by the cell shapes. + Applies a funnel algorithm to the raw path corridor found by the pathfinding algorithm. This will result in the shortest path possible inside the path corridor. This postprocessing very much depends on the navigation mesh polygon layout and the created corridor. Especially tile- or gridbased layouts can face artificial corners with diagonal movement due to a jagged path corridor imposed by the cell shapes. </constant> <constant name="PATH_POSTPROCESSING_EDGECENTERED" value="1" enum="PathPostProcessing"> - Centers every path position in the middle of the traveled navmesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center. + Centers every path position in the middle of the traveled navigation mesh polygon edge. This creates better paths for tile- or gridbased layouts that restrict the movement to the cells center. + </constant> + <constant name="PATH_METADATA_INCLUDE_NONE" value="0" enum="PathMetadataFlags" is_bitfield="true"> + Don't include any additional metadata about the returned path. + </constant> + <constant name="PATH_METADATA_INCLUDE_TYPES" value="1" enum="PathMetadataFlags" is_bitfield="true"> + Include the type of navigation primitive (region or link) that each point of the path goes through. + </constant> + <constant name="PATH_METADATA_INCLUDE_RIDS" value="2" enum="PathMetadataFlags" is_bitfield="true"> + Include the [RID]s of the regions and links that each point of the path goes through. + </constant> + <constant name="PATH_METADATA_INCLUDE_OWNERS" value="4" enum="PathMetadataFlags" is_bitfield="true"> + Include the [code]ObjectID[/code]s of the [Object]s which manage the regions and links each point of the path goes through. + </constant> + <constant name="PATH_METADATA_INCLUDE_ALL" value="7" enum="PathMetadataFlags" is_bitfield="true"> + Include all available metadata about the returned path. </constant> </constants> </class> diff --git a/doc/classes/NavigationPathQueryResult2D.xml b/doc/classes/NavigationPathQueryResult2D.xml index 95b90e9383..75f7cc47aa 100644 --- a/doc/classes/NavigationPathQueryResult2D.xml +++ b/doc/classes/NavigationPathQueryResult2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationPathQueryResult2D" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationPathQueryResult2D" inherits="RefCounted" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Result from a [NavigationPathQueryParameters2D] navigation path query. </brief_description> @@ -20,5 +20,22 @@ <member name="path" type="PackedVector2Array" setter="set_path" getter="get_path" default="PackedVector2Array()"> The resulting path array from the navigation query. All path array positions are in global coordinates. Without customized query parameters this is the same path as returned by [method NavigationServer2D.map_get_path]. </member> + <member name="path_owner_ids" type="PackedInt64Array" setter="set_path_owner_ids" getter="get_path_owner_ids" default="PackedInt64Array()"> + The [code]ObjectID[/code]s of the [Object]s which manage the regions and links each point of the path goes through. + </member> + <member name="path_rids" type="RID[]" setter="set_path_rids" getter="get_path_rids" default="[]"> + The [RID]s of the regions and links that each point of the path goes through. + </member> + <member name="path_types" type="PackedInt32Array" setter="set_path_types" getter="get_path_types" default="PackedInt32Array()"> + The type of navigation primitive (region or link) that each point of the path goes through. + </member> </members> + <constants> + <constant name="PATH_SEGMENT_TYPE_REGION" value="0" enum="PathSegmentType"> + This segment of the path goes through a region. + </constant> + <constant name="PATH_SEGMENT_TYPE_LINK" value="1" enum="PathSegmentType"> + This segment of the path goes through a link. + </constant> + </constants> </class> diff --git a/doc/classes/NavigationPathQueryResult3D.xml b/doc/classes/NavigationPathQueryResult3D.xml index b4ca8288db..03d41cb230 100644 --- a/doc/classes/NavigationPathQueryResult3D.xml +++ b/doc/classes/NavigationPathQueryResult3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationPathQueryResult3D" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationPathQueryResult3D" inherits="RefCounted" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Result from a [NavigationPathQueryParameters3D] navigation path query. </brief_description> @@ -20,5 +20,22 @@ <member name="path" type="PackedVector3Array" setter="set_path" getter="get_path" default="PackedVector3Array()"> The resulting path array from the navigation query. All path array positions are in global coordinates. Without customized query parameters this is the same path as returned by [method NavigationServer3D.map_get_path]. </member> + <member name="path_owner_ids" type="PackedInt64Array" setter="set_path_owner_ids" getter="get_path_owner_ids" default="PackedInt64Array()"> + The [code]ObjectID[/code]s of the [Object]s which manage the regions and links each point of the path goes through. + </member> + <member name="path_rids" type="RID[]" setter="set_path_rids" getter="get_path_rids" default="[]"> + The [RID]s of the regions and links that each point of the path goes through. + </member> + <member name="path_types" type="PackedInt32Array" setter="set_path_types" getter="get_path_types" default="PackedInt32Array()"> + The type of navigation primitive (region or link) that each point of the path goes through. + </member> </members> + <constants> + <constant name="PATH_SEGMENT_TYPE_REGION" value="0" enum="PathSegmentType"> + This segment of the path goes through a region. + </constant> + <constant name="PATH_SEGMENT_TYPE_LINK" value="1" enum="PathSegmentType"> + This segment of the path goes through a link. + </constant> + </constants> </class> diff --git a/doc/classes/NavigationPolygon.xml b/doc/classes/NavigationPolygon.xml index 19466c171f..b30dd2703a 100644 --- a/doc/classes/NavigationPolygon.xml +++ b/doc/classes/NavigationPolygon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationPolygon" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationPolygon" inherits="Resource" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A node that has methods to draw outlines or use indices of vertices to create navigation polygons. </brief_description> @@ -12,14 +12,14 @@ var outline = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)]) polygon.add_outline(outline) polygon.make_polygons_from_outlines() - $NavigationRegion2D.navpoly = polygon + $NavigationRegion2D.navigation_polygon = polygon [/gdscript] [csharp] var polygon = new NavigationPolygon(); var outline = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) }; polygon.AddOutline(outline); polygon.MakePolygonsFromOutlines(); - GetNode<NavigationRegion2D>("NavigationRegion2D").Navpoly = polygon; + GetNode<NavigationRegion2D>("NavigationRegion2D").NavigationPolygon = polygon; [/csharp] [/codeblocks] Using [method add_polygon] and indices of the vertices array. @@ -30,7 +30,7 @@ polygon.vertices = vertices var indices = PackedInt32Array([0, 1, 2, 3]) polygon.add_polygon(indices) - $NavigationRegion2D.navpoly = polygon + $NavigationRegion2D.navigation_polygon = polygon [/gdscript] [csharp] var polygon = new NavigationPolygon(); @@ -38,7 +38,7 @@ polygon.Vertices = vertices; var indices = new int[] { 0, 1, 2, 3 }; polygon.AddPolygon(indices); - GetNode<NavigationRegion2D>("NavigationRegion2D").Navpoly = polygon; + GetNode<NavigationRegion2D>("NavigationRegion2D").NavigationPolygon = polygon; [/csharp] [/codeblocks] </description> @@ -80,10 +80,10 @@ Clears the array of polygons, but it doesn't clear the array of outlines and vertices. </description> </method> - <method name="get_mesh"> + <method name="get_navigation_mesh"> <return type="NavigationMesh" /> <description> - Returns the [NavigationMesh] resulting from this navigation polygon. This navmesh can be used to update the navmesh of a region with the [method NavigationServer3D.region_set_navmesh] API directly (as 2D uses the 3D server behind the scene). + Returns the [NavigationMesh] resulting from this navigation polygon. This navigation mesh can be used to update the navigation mesh of a region with the [method NavigationServer3D.region_set_navigation_mesh] API directly (as 2D uses the 3D server behind the scene). </description> </method> <method name="get_outline" qualifiers="const"> diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml index 0f28081201..8b8793b3b4 100644 --- a/doc/classes/NavigationRegion2D.xml +++ b/doc/classes/NavigationRegion2D.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationRegion2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationRegion2D" inherits="Node2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A region of the 2D navigation map. </brief_description> <description> A region of the navigation map. It tells the [NavigationServer2D] what can be navigated and what cannot, based on its [NavigationPolygon] resource. Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer2D.map_set_edge_connection_margin]. - [b]Note:[/b] Overlapping two regions' polygons is not enough for connecting two regions. They must share a similar edge. + [b]Note:[/b] Overlapping two regions' navigation polygons is not enough for connecting two regions. They must share a similar edge. The pathfinding cost of entering this region from another region can be controlled with the [member enter_cost] value. [b]Note:[/b] This value is not added to the path cost when the start position is already inside this region. The pathfinding cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier. @@ -42,16 +42,16 @@ Determines if the [NavigationRegion2D] is enabled or disabled. </member> <member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0"> - When pathfinding enters this region's navmesh from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path. + When pathfinding enters this region's navigation mesh from another regions navigation mesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path. </member> <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> A bitfield determining all navigation layers the region belongs to. These navigation layers can be checked upon when requesting a path with [method NavigationServer2D.map_get_path]. </member> - <member name="navpoly" type="NavigationPolygon" setter="set_navigation_polygon" getter="get_navigation_polygon"> + <member name="navigation_polygon" type="NavigationPolygon" setter="set_navigation_polygon" getter="get_navigation_polygon"> The [NavigationPolygon] resource to use. </member> <member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0"> - When pathfinding moves inside this region's navmesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path. + When pathfinding moves inside this region's navigation mesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path. </member> </members> </class> diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml index 85f163b3c2..10662db869 100644 --- a/doc/classes/NavigationRegion3D.xml +++ b/doc/classes/NavigationRegion3D.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationRegion3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationRegion3D" inherits="Node3D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> A region of the navigation map. </brief_description> <description> A region of the navigation map. It tells the [NavigationServer3D] what can be navigated and what cannot, based on its [NavigationMesh] resource. Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer3D.map_set_edge_connection_margin]. - [b]Note:[/b] Overlapping two regions' navmeshes is not enough for connecting two regions. They must share a similar edge. + [b]Note:[/b] Overlapping two regions' navigation meshes is not enough for connecting two regions. They must share a similar edge. The cost of entering this region from another region can be controlled with the [member enter_cost] value. [b]Note:[/b] This value is not added to the path cost when the start position is already inside this region. The cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier. @@ -49,16 +49,16 @@ Determines if the [NavigationRegion3D] is enabled or disabled. </member> <member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0"> - When pathfinding enters this region's navmesh from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path. + When pathfinding enters this region's navigation mesh from another regions navigation mesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path. </member> <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> A bitfield determining all navigation layers the region belongs to. These navigation layers can be checked upon when requesting a path with [method NavigationServer3D.map_get_path]. </member> - <member name="navmesh" type="NavigationMesh" setter="set_navigation_mesh" getter="get_navigation_mesh"> + <member name="navigation_mesh" type="NavigationMesh" setter="set_navigation_mesh" getter="get_navigation_mesh"> The [NavigationMesh] resource to use. </member> <member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0"> - When pathfinding moves inside this region's navmesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path. + When pathfinding moves inside this region's navigation mesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path. </member> </members> <signals> diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml index 230e58a12a..32e48cde54 100644 --- a/doc/classes/NavigationServer2D.xml +++ b/doc/classes/NavigationServer2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationServer2D" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationServer2D" inherits="Object" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Server interface for low-level 2D navigation access </brief_description> @@ -489,12 +489,12 @@ Set the region's navigation layers. This allows selecting regions from a path request (when using [method NavigationServer2D.map_get_path]). </description> </method> - <method name="region_set_navpoly" qualifiers="const"> + <method name="region_set_navigation_polygon" qualifiers="const"> <return type="void" /> <param index="0" name="region" type="RID" /> - <param index="1" name="nav_poly" type="NavigationPolygon" /> + <param index="1" name="navigation_polygon" type="NavigationPolygon" /> <description> - Sets the navigation mesh for the region. + Sets the [param navigation_polygon] for the region. </description> </method> <method name="region_set_owner_id" qualifiers="const"> diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index c7da3b7b5b..c156dfac16 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NavigationServer3D" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="NavigationServer3D" inherits="Object" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Server interface for low-level 3D navigation access </brief_description> @@ -433,12 +433,12 @@ Queries a path in a given navigation map. Start and target position and other parameters are defined through [NavigationPathQueryParameters3D]. Updates the provided [NavigationPathQueryResult3D] result object with the path among other results requested by the query. </description> </method> - <method name="region_bake_navmesh" qualifiers="const"> + <method name="region_bake_navigation_mesh" qualifiers="const"> <return type="void" /> - <param index="0" name="mesh" type="NavigationMesh" /> - <param index="1" name="node" type="Node" /> + <param index="0" name="navigation_mesh" type="NavigationMesh" /> + <param index="1" name="root_node" type="Node" /> <description> - Bakes the navigation mesh. + Bakes the [param navigation_mesh] with bake source geometry collected starting from the [param root_node]. </description> </method> <method name="region_create" qualifiers="const"> @@ -539,10 +539,10 @@ Set the region's navigation layers. This allows selecting regions from a path request (when using [method NavigationServer3D.map_get_path]). </description> </method> - <method name="region_set_navmesh" qualifiers="const"> + <method name="region_set_navigation_mesh" qualifiers="const"> <return type="void" /> <param index="0" name="region" type="RID" /> - <param index="1" name="nav_mesh" type="NavigationMesh" /> + <param index="1" name="navigation_mesh" type="NavigationMesh" /> <description> Sets the navigation mesh for the region. </description> diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml index 26efe37dce..9d224f09b1 100644 --- a/doc/classes/Node2D.xml +++ b/doc/classes/Node2D.xml @@ -99,6 +99,9 @@ <member name="global_rotation" type="float" setter="set_global_rotation" getter="get_global_rotation"> Global rotation in radians. </member> + <member name="global_rotation_degrees" type="float" setter="set_global_rotation_degrees" getter="get_global_rotation_degrees"> + Helper property to access [member global_rotation] in degrees instead of radians. + </member> <member name="global_scale" type="Vector2" setter="set_global_scale" getter="get_global_scale"> Global scale. </member> @@ -114,6 +117,9 @@ <member name="rotation" type="float" setter="set_rotation" getter="get_rotation" default="0.0"> Rotation in radians, relative to the node's parent. </member> + <member name="rotation_degrees" type="float" setter="set_rotation_degrees" getter="get_rotation_degrees"> + Helper property to access [member rotation] in degrees instead of radians. + </member> <member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2(1, 1)"> The node's scale. Unscaled value: [code](1, 1)[/code]. [b]Note:[/b] Negative X scales in 2D are not decomposable from the transformation matrix. Due to the way scale is represented with transformation matrices in Godot, negative scales on the X axis will be changed to negative scales on the Y axis and a rotation of 180 degrees when decomposed. diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml index b6024b1887..1aa71113e9 100644 --- a/doc/classes/Node3D.xml +++ b/doc/classes/Node3D.xml @@ -274,6 +274,9 @@ Rotation part of the global transformation in radians, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle). [b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful. </member> + <member name="global_rotation_degrees" type="Vector3" setter="set_global_rotation_degrees" getter="get_global_rotation_degrees"> + Helper property to access [member global_rotation] in degrees instead of radians. + </member> <member name="global_transform" type="Transform3D" setter="set_global_transform" getter="get_global_transform"> World3D space (global) [Transform3D] of this node. </member> @@ -287,6 +290,9 @@ Rotation part of the local transformation in radians, specified in terms of Euler angles. The angles construct a rotaton in the order specified by the [member rotation_order] property. [b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful. </member> + <member name="rotation_degrees" type="Vector3" setter="set_rotation_degrees" getter="get_rotation_degrees"> + Helper property to access [member rotation] in degrees instead of radians. + </member> <member name="rotation_edit_mode" type="int" setter="set_rotation_edit_mode" getter="get_rotation_edit_mode" enum="Node3D.RotationEditMode" default="0"> Specify how rotation (and scale) will be presented in the editor. </member> diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index e63e822648..a58a6249ae 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -259,6 +259,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> [Font] of the [OptionButton]'s text. diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml index 18ac8a11df..2d25965180 100644 --- a/doc/classes/PhysicsServer2D.xml +++ b/doc/classes/PhysicsServer2D.xml @@ -736,6 +736,14 @@ <description> </description> </method> + <method name="joint_disable_collisions_between_bodies"> + <return type="void" /> + <param index="0" name="joint" type="RID" /> + <param index="1" name="disable" type="bool" /> + <description> + Sets whether the bodies attached to the [Joint2D] will collide with each other. + </description> + </method> <method name="joint_get_param" qualifiers="const"> <return type="float" /> <param index="0" name="joint" type="RID" /> @@ -751,6 +759,13 @@ Returns a joint's type (see [enum JointType]). </description> </method> + <method name="joint_is_disabled_collisions_between_bodies" qualifiers="const"> + <return type="bool" /> + <param index="0" name="joint" type="RID" /> + <description> + Returns whether the bodies attached to the [Joint2D] will collide with each other. + </description> + </method> <method name="joint_make_damped_spring"> <return type="void" /> <param index="0" name="joint" type="RID" /> diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 95f7fb69a2..e62bda0dd3 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -815,6 +815,14 @@ <description> </description> </method> + <method name="joint_disable_collisions_between_bodies"> + <return type="void" /> + <param index="0" name="joint" type="RID" /> + <param index="1" name="disable" type="bool" /> + <description> + Sets whether the bodies attached to the [Joint3D] will collide with each other. + </description> + </method> <method name="joint_get_solver_priority" qualifiers="const"> <return type="int" /> <param index="0" name="joint" type="RID" /> @@ -829,6 +837,13 @@ Returns the type of the Joint3D. </description> </method> + <method name="joint_is_disabled_collisions_between_bodies" qualifiers="const"> + <return type="bool" /> + <param index="0" name="joint" type="RID" /> + <description> + Returns whether the bodies attached to the [Joint3D] will collide with each other. + </description> + </method> <method name="joint_make_cone_twist"> <return type="void" /> <param index="0" name="joint" type="RID" /> diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml index 1e9df54de5..d45cb17510 100644 --- a/doc/classes/PhysicsServer3DExtension.xml +++ b/doc/classes/PhysicsServer3DExtension.xml @@ -772,6 +772,13 @@ <description> </description> </method> + <method name="_joint_disable_collisions_between_bodies" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="joint" type="RID" /> + <param index="1" name="disable" type="bool" /> + <description> + </description> + </method> <method name="_joint_get_solver_priority" qualifiers="virtual const"> <return type="int" /> <param index="0" name="joint" type="RID" /> @@ -784,6 +791,12 @@ <description> </description> </method> + <method name="_joint_is_disabled_collisions_between_bodies" qualifiers="virtual const"> + <return type="bool" /> + <param index="0" name="joint" type="RID" /> + <description> + </description> + </method> <method name="_joint_make_cone_twist" qualifiers="virtual"> <return type="void" /> <param index="0" name="joint" type="RID" /> diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index 6810b0e8e4..8dec4eaf86 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -584,6 +584,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the item text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="separator_outline_size" data_type="constant" type="int" default="0"> The size of the labeled separator text outline. diff --git a/doc/classes/ProgressBar.xml b/doc/classes/ProgressBar.xml index 510b8d5bd1..9f89a4e4c3 100644 --- a/doc/classes/ProgressBar.xml +++ b/doc/classes/ProgressBar.xml @@ -42,6 +42,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> Font used to draw the fill percentage if [member show_percentage] is [code]true[/code]. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 72f9a0e32f..67b692a7a0 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -70,15 +70,18 @@ <method name="get_setting" qualifiers="const"> <return type="Variant" /> <param index="0" name="name" type="String" /> + <param index="1" name="default_value" type="Variant" default="null" /> <description> - Returns the value of a setting. + Returns the value of the setting identified by [param name]. If the setting doesn't exist and [param default_value] is specified, the value of [param default_value] is returned. Otherwise, [code]null[/code] is returned. [b]Example:[/b] [codeblocks] [gdscript] print(ProjectSettings.get_setting("application/config/name")) + print(ProjectSettings.get_setting("application/config/custom_description", "No description specified.")) [/gdscript] [csharp] GD.Print(ProjectSettings.GetSetting("application/config/name")); + GD.Print(ProjectSettings.GetSetting("application/config/custom_description", "No description specified.")); [/csharp] [/codeblocks] </description> @@ -344,9 +347,6 @@ <member name="compression/formats/zstd/window_log_size" type="int" setter="" getter="" default="27"> Largest size limit (in power of 2) allowed when compressing using long-distance matching with Zstandard. Higher values can result in better compression, but will require more memory when compressing and decompressing. </member> - <member name="debug/disable_touch" type="bool" setter="" getter="" default="false"> - Disable touch input. Only has effect on iOS. - </member> <member name="debug/file_logging/enable_file_logging" type="bool" setter="" getter="" default="false"> If [code]true[/code], logs all output to files. </member> @@ -585,7 +585,7 @@ [b]Note:[/b] This setting has no effect on the home indicator if [code]hide_home_indicator[/code] is [code]true[/code]. </member> <member name="display/window/per_pixel_transparency/allowed" type="bool" setter="" getter="" default="false"> - If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it. See also [member display/window/size/transparent] and [member rendering/transparent_background]. + If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it. See also [member display/window/size/transparent] and [member rendering/viewport/transparent_background]. </member> <member name="display/window/size/always_on_top" type="bool" setter="" getter="" default="false"> Forces the main window to be always on top. @@ -610,7 +610,7 @@ [b]Note:[/b] This setting is ignored on iOS. </member> <member name="display/window/size/transparent" type="bool" setter="" getter="" default="false"> - If [code]true[/code], enables a window manager hint that the main window background [i]can[/i] be transparent. This does not make the background actually transparent. For the background to be transparent, the root viewport must also be made transparent by enabling [member rendering/transparent_background]. + If [code]true[/code], enables a window manager hint that the main window background [i]can[/i] be transparent. This does not make the background actually transparent. For the background to be transparent, the root viewport must also be made transparent by enabling [member rendering/viewport/transparent_background]. [b]Note:[/b] To use a transparent splash screen, set [member application/boot_splash/bg_color] to [code]Color(0, 0, 0, 0)[/code]. [b]Note:[/b] This setting has no effect if [member display/window/per_pixel_transparency/allowed] is set to [code]false[/code]. </member> @@ -2256,7 +2256,7 @@ <member name="rendering/textures/webp_compression/lossless_compression_factor" type="float" setter="" getter="" default="25"> The default compression factor for lossless WebP. Decompression speed is mostly unaffected by the compression factor. Supported values are 0 to 100. </member> - <member name="rendering/transparent_background" type="bool" setter="" getter="" default="false"> + <member name="rendering/viewport/transparent_background" type="bool" setter="" getter="" default="false"> If [code]true[/code], enables [member Viewport.transparent_bg] on the root viewport. This allows per-pixel transparency to be effective after also enabling [member display/window/size/transparent] and [member display/window/per_pixel_transparency/allowed]. </member> <member name="rendering/vrs/mode" type="int" setter="" getter="" default="0"> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index d9b83f2acd..87e569ba20 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -241,6 +241,7 @@ <param index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" /> <param index="5" name="outline_size" type="int" default="0" /> <param index="6" name="px_range" type="float" default="1.0" /> + <param index="7" name="scale" type="float" default="1.0" /> <description> </description> </method> @@ -1585,6 +1586,15 @@ Sets the render layers that this instance will be drawn to. Equivalent to [member VisualInstance3D.layers]. </description> </method> + <method name="instance_set_pivot_data"> + <return type="void" /> + <param index="0" name="instance" type="RID" /> + <param index="1" name="sorting_offset" type="float" /> + <param index="2" name="use_aabb_center" type="bool" /> + <description> + Sets the sorting offset and switches between using the bounding box or instance origin for depth sorting. + </description> + </method> <method name="instance_set_scenario"> <return type="void" /> <param index="0" name="instance" type="RID" /> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index f587ababfe..dd291a425d 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -378,12 +378,12 @@ Adds a [code][u][/code] tag to the tag stack. </description> </method> - <method name="remove_line"> + <method name="remove_paragraph"> <return type="bool" /> - <param index="0" name="line" type="int" /> + <param index="0" name="paragraph" type="int" /> <description> - Removes a line of content from the label. Returns [code]true[/code] if the line exists. - The [param line] argument is the index of the line to remove, it can take values in the interval [code][0, get_line_count() - 1][/code]. + Removes a paragraph of content from the label. Returns [code]true[/code] if the paragraph exists. + The [param paragraph] argument is the index of the paragraph to remove, it can take values in the interval [code][0, get_paragraph_count() - 1][/code]. </description> </method> <method name="scroll_to_line"> @@ -656,6 +656,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="shadow_offset_x" data_type="constant" type="int" default="1"> The horizontal offset of the font's shadow. diff --git a/doc/classes/TabBar.xml b/doc/classes/TabBar.xml index 713c016651..8d56cbda13 100644 --- a/doc/classes/TabBar.xml +++ b/doc/classes/TabBar.xml @@ -319,6 +319,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the tab text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> The font used to draw tab names. diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml index e2e7a0c37e..c744c9b439 100644 --- a/doc/classes/TabContainer.xml +++ b/doc/classes/TabContainer.xml @@ -214,6 +214,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the tab text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="side_margin" data_type="constant" type="int" default="8"> The space at the left or right edges of the tab bar, accordingly with the current [member tab_alignment]. diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index d4f5233438..1efd0f9326 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -1396,6 +1396,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="font" data_type="font" type="Font"> Sets the default [Font]. diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index 637e502d49..d2c6dee373 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -930,6 +930,7 @@ <param index="1" name="language" type="String" default="""" /> <description> Converts a number from the Western Arabic (0..9) to the numeral systems used in [param language]. + If [param language] is omitted, the active locale will be used. </description> </method> <method name="free_rid"> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index 629c271417..584a2a2a7b 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -522,6 +522,7 @@ </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> The size of the text outline. + [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> <theme_item name="parent_hl_line_margin" data_type="constant" type="int" default="0"> The space between the parent relationship lines for the selected [TreeItem] and the relationship lines to its siblings that are not selected. diff --git a/doc/classes/TubeTrailMesh.xml b/doc/classes/TubeTrailMesh.xml index ddc544dc97..7457aa4050 100644 --- a/doc/classes/TubeTrailMesh.xml +++ b/doc/classes/TubeTrailMesh.xml @@ -7,6 +7,12 @@ <tutorials> </tutorials> <members> + <member name="cap_bottom" type="bool" setter="set_cap_bottom" getter="is_cap_bottom" default="true"> + If [code]true[/code], generates a cap at the bottom of the tube. This can be set to [code]false[/code] to speed up generation and rendering when the cap is never seen by the camera. + </member> + <member name="cap_top" type="bool" setter="set_cap_top" getter="is_cap_top" default="true"> + If [code]true[/code], generates a cap at the top of the tube. This can be set to [code]false[/code] to speed up generation and rendering when the cap is never seen by the camera. + </member> <member name="curve" type="Curve" setter="set_curve" getter="get_curve"> </member> <member name="radial_steps" type="int" setter="set_radial_steps" getter="get_radial_steps" default="8"> diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml index 31811f817b..e069642e50 100644 --- a/doc/classes/VisualInstance3D.xml +++ b/doc/classes/VisualInstance3D.xml @@ -61,5 +61,12 @@ This object will only be visible for [Camera3D]s whose cull mask includes the render object this [VisualInstance3D] is set to. For [Light3D]s, this can be used to control which [VisualInstance3D]s are affected by a specific light. For [GPUParticles3D], this can be used to control which particles are effected by a specific attractor. For [Decal]s, this can be used to control which [VisualInstance3D]s are affected by a specific decal. </member> + <member name="sorting_offset" type="float" setter="set_sorting_offset" getter="get_sorting_offset" default="0.0"> + The sorting offset used by this [VisualInstance3D]. Adjusting it to a higher value will make the [VisualInstance3D] reliably draw on top of other [VisualInstance3D]s that are otherwise positioned at the same spot. + </member> + <member name="sorting_use_aabb_center" type="bool" setter="set_sorting_use_aabb_center" getter="is_sorting_use_aabb_center" default="true"> + If [code]true[/code], the object is sorted based on the [AABB] center. The object will be sorted based on the global position otherwise. + The [AABB] center based sorting is generally more accurate for 3D models. The position based sorting instead allows to better control the drawing order when working with [GPUParticles3D] and [CPUParticles3D]. + </member> </members> </class> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 2b44043faf..1faecfd4d0 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1170,12 +1170,17 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const for (int i = 0; i < (int)p_render_data->instances->size(); i++) { GeometryInstanceGLES3 *inst = static_cast<GeometryInstanceGLES3 *>((*p_render_data->instances)[i]); + Vector3 center = inst->transform.origin; if (p_render_data->cam_orthogonal) { - Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); - inst->depth = near_plane.distance_to(support_min); + if (inst->use_aabb_center) { + center = inst->transformed_aabb.get_support(-near_plane.normal); + } + inst->depth = near_plane.distance_to(center) - inst->sorting_offset; } else { - Vector3 aabb_center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5); - inst->depth = p_render_data->cam_transform.origin.distance_to(aabb_center); + if (inst->use_aabb_center) { + center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5); + } + inst->depth = p_render_data->cam_transform.origin.distance_to(center) - inst->sorting_offset; } uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index b02a100784..711fd7b962 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -152,12 +152,10 @@ Vector<String> OS_Unix::get_video_adapter_driver_info() const { String OS_Unix::get_stdin_string(bool p_block) { if (p_block) { char buff[1024]; - String ret = stdin_buf + fgets(buff, 1024, stdin); - stdin_buf = ""; - return ret; + return String::utf8(fgets(buff, 1024, stdin)); } - return ""; + return String(); } Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) { diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index ce06a52a95..68d2dd0042 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -46,8 +46,6 @@ protected: virtual void finalize_core() override; - String stdin_buf; - public: OS_Unix(); diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index f9348311a4..b982ab3e40 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -995,8 +995,11 @@ void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFor case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc. - case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: - case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: + case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: { + r_w = 4; + r_h = 4; + } break; + case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: // Unsupported case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: @@ -1007,10 +1010,16 @@ void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFor case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: - case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: { + r_w = 4; + r_h = 4; + } break; case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: - case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: - case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: { + r_w = 8; + r_h = 8; + } break; + case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: // Unsupported case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: @@ -1100,7 +1109,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: - return 8; // Wrong. + return 16; default: { } } @@ -1122,6 +1131,10 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor case DATA_FORMAT_EAC_R11_UNORM_BLOCK: case DATA_FORMAT_EAC_R11_SNORM_BLOCK: return 1; + case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: { + return 2; + } default: { } } diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index c376d5434f..a1e4b5fde4 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -35,6 +35,7 @@ #include "editor/input_event_configuration_dialog.h" #include "scene/gui/check_button.h" #include "scene/gui/tree.h" +#include "scene/scene_string_names.h" static bool _is_action_name_valid(const String &p_name) { const char32_t *cstr = p_name.get_data(); @@ -362,6 +363,8 @@ void ActionMapEditor::_bind_methods() { ADD_SIGNAL(MethodInfo("action_removed", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("action_renamed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name"))); ADD_SIGNAL(MethodInfo("action_reordered", PropertyInfo(Variant::STRING, "action_name"), PropertyInfo(Variant::STRING, "relative_to"), PropertyInfo(Variant::BOOL, "before"))); + ADD_SIGNAL(MethodInfo(SNAME("filter_focused"))); + ADD_SIGNAL(MethodInfo(SNAME("filter_unfocused"))); } LineEdit *ActionMapEditor::get_search_box() const { @@ -492,6 +495,14 @@ void ActionMapEditor::use_external_search_box(LineEdit *p_searchbox) { action_list_search->connect("text_changed", callable_mp(this, &ActionMapEditor::_search_term_updated)); } +void ActionMapEditor::_on_filter_focused() { + emit_signal(SNAME("filter_focused")); +} + +void ActionMapEditor::_on_filter_unfocused() { + emit_signal(SNAME("filter_unfocused")); +} + ActionMapEditor::ActionMapEditor() { // Main Vbox Container VBoxContainer *main_vbox = memnew(VBoxContainer); @@ -512,6 +523,8 @@ ActionMapEditor::ActionMapEditor() { action_list_search_by_event->set_h_size_flags(Control::SIZE_EXPAND_FILL); action_list_search_by_event->set_stretch_ratio(0.75); action_list_search_by_event->connect("event_changed", callable_mp(this, &ActionMapEditor::_search_by_event)); + action_list_search_by_event->connect(SceneStringNames::get_singleton()->focus_entered, callable_mp(this, &ActionMapEditor::_on_filter_focused)); + action_list_search_by_event->connect(SceneStringNames::get_singleton()->focus_exited, callable_mp(this, &ActionMapEditor::_on_filter_unfocused)); top_hbox->add_child(action_list_search_by_event); Button *clear_all_search = memnew(Button); diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h index ad9980c4ef..1908805b17 100644 --- a/editor/action_map_editor.h +++ b/editor/action_map_editor.h @@ -106,6 +106,9 @@ private: bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + void _on_filter_focused(); + void _on_filter_unfocused(); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 530708f3e5..7b5a7b7046 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -575,7 +575,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) { ep.point_rect.size = bezier_icon->get_size(); if (selection.has(IntPair(i, j))) { draw_texture(selected_icon, ep.point_rect.position); - draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent); + draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.0001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent); draw_string(font, ep.point_rect.position + Vector2(8, -8), TTR("Value:") + " " + TS->format_number(rtos(Math::snapped(value, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent); } else { Color track_color = Color(1, 1, 1, 1); @@ -812,7 +812,7 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int return; } - int idx = animation->track_find_key(p_track, p_pos, true); + int idx = animation->track_find_key(p_track, p_pos, Animation::FIND_MODE_APPROX); ERR_FAIL_COND(idx < 0); selection.insert(IntPair(p_track, idx)); @@ -1168,8 +1168,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { new_point[4] = 0; real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); - while (animation->track_find_key(selected_track, time, true) != -1) { - time += 0.001; + while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) { + time += 0.0001; } Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); @@ -1179,7 +1179,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { undo_redo->commit_action(); //then attempt to move - int index = animation->track_find_key(selected_track, time, true); + int index = animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX); ERR_FAIL_COND(index == -1); _clear_selection(); selection.insert(IntPair(selected_track, index)); @@ -1283,7 +1283,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); - int idx = animation->track_find_key(E->get().first, newtime, true); + int idx = animation->track_find_key(E->get().first, newtime, Animation::FIND_MODE_APPROX); if (idx == -1) { continue; } @@ -1539,7 +1539,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); - while (animation->track_find_key(selected_track, time, true) != -1) { + while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) { time += 0.001; } @@ -1599,7 +1599,7 @@ void AnimationBezierTrackEdit::duplicate_selection() { for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { real_t t = animation->track_get_key_time(E->get().first, E->get().second); real_t dst_time = t + (timeline->get_play_position() - top_time); - int existing_idx = animation->track_find_key(E->get().first, dst_time, true); + int existing_idx = animation->track_find_key(E->get().first, dst_time, Animation::FIND_MODE_APPROX); undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, E->get().second), animation->track_get_key_transition(E->get().first, E->get().second)); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, dst_time); @@ -1623,7 +1623,7 @@ void AnimationBezierTrackEdit::duplicate_selection() { int track = E.first; real_t time = E.second; - int existing_idx = animation->track_find_key(track, time, true); + int existing_idx = animation->track_find_key(track, time, Animation::FIND_MODE_APPROX); if (existing_idx == -1) { continue; diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 2ee06a0dbd..74e0db967d 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -48,1356 +48,1182 @@ #include "scene/scene_string_names.h" #include "servers/audio/audio_stream.h" -class AnimationTrackKeyEdit : public Object { - GDCLASS(AnimationTrackKeyEdit, Object); - -public: - bool setting = false; - bool animation_read_only = false; +void AnimationTrackKeyEdit::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj); + ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed); + ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector); + ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationTrackKeyEdit::_hide_metadata_from_inspector); + ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path); + ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo); + ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only); +} - bool _hide_script_from_inspector() { return true; } - bool _hide_metadata_from_inspector() { return true; } - bool _dont_undo_redo() { return true; } +void AnimationTrackKeyEdit::_fix_node_path(Variant &value) { + NodePath np = value; - bool _is_read_only() { - return animation_read_only; + if (np == NodePath()) { + return; } - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj); - ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed); - ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector); - ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationTrackKeyEdit::_hide_metadata_from_inspector); - ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path); - ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo); - ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only); - } + Node *root = EditorNode::get_singleton()->get_tree()->get_root(); - void _fix_node_path(Variant &value) { - NodePath np = value; + Node *np_node = root->get_node(np); + ERR_FAIL_COND(!np_node); - if (np == NodePath()) { - return; - } + Node *edited_node = root->get_node(base); + ERR_FAIL_COND(!edited_node); - Node *root = EditorNode::get_singleton()->get_tree()->get_root(); + value = edited_node->get_path_to(np_node); +} - Node *np_node = root->get_node(np); - ERR_FAIL_COND(!np_node); +void AnimationTrackKeyEdit::_update_obj(const Ref<Animation> &p_anim) { + if (setting || animation != p_anim) { + return; + } - Node *edited_node = root->get_node(base); - ERR_FAIL_COND(!edited_node); + notify_change(); +} - value = edited_node->get_path_to(np_node); +void AnimationTrackKeyEdit::_key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) { + if (animation != p_anim || from != key_ofs) { + return; } - void _update_obj(const Ref<Animation> &p_anim) { - if (setting || animation != p_anim) { - return; - } + key_ofs = to; - notify_change(); + if (setting) { + return; } - void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) { - if (animation != p_anim || from != key_ofs) { - return; - } + notify_change(); +} - key_ofs = to; +bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_value) { + int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX); + ERR_FAIL_COND_V(key == -1, false); - if (setting) { - return; - } + String name = p_name; + if (name == "easing") { + float val = p_value; + float prev_val = animation->track_get_key_transition(track, key); + setting = true; + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + undo_redo->create_action(TTR("Animation Change Transition"), UndoRedo::MERGE_ENDS); + undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); - notify_change(); + setting = false; + return true; } - bool _set(const StringName &p_name, const Variant &p_value) { - int key = animation->track_find_key(track, key_ofs, true); - ERR_FAIL_COND_V(key == -1, false); - - String name = p_name; - if (name == "time" || name == "frame") { - float new_time = p_value; - - if (name == "frame") { - float fps = animation->get_step(); - if (fps > 0) { - fps = 1.0 / fps; + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + switch (animation->track_get_type(track)) { + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { + if (name == "position" || name == "rotation" || name == "scale") { + Variant old = animation->track_get_key_value(track, key); + setting = true; + String chan; + switch (animation->track_get_type(track)) { + case Animation::TYPE_POSITION_3D: + chan = "Position3D"; + break; + case Animation::TYPE_ROTATION_3D: + chan = "Rotation3D"; + break; + case Animation::TYPE_SCALE_3D: + chan = "Scale3D"; + break; + default: { + } } - new_time /= fps; - } - if (new_time == key_ofs) { + undo_redo->create_action(vformat(TTR("Animation Change %s"), chan)); + undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); + + setting = false; return true; } - int existing = animation->track_find_key(track, new_time, true); + } break; + case Animation::TYPE_BLEND_SHAPE: + case Animation::TYPE_VALUE: { + if (name == "value") { + Variant value = p_value; - setting = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS); + if (value.get_type() == Variant::NODE_PATH) { + _fix_node_path(value); + } - Variant val = animation->track_get_key_value(track, key); - float trans = animation->track_get_key_transition(track, key); + setting = true; + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); + Variant prev = animation->track_get_key_value(track, key); + undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); - undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key); - undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans); - undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time); - undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time); - undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans); - undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs); + setting = false; + return true; + } + } break; + case Animation::TYPE_METHOD: { + Dictionary d_old = animation->track_get_key_value(track, key); + Dictionary d_new = d_old.duplicate(); + + bool change_notify_deserved = false; + bool mergeable = false; + + if (name == "name") { + d_new["method"] = p_value; + } else if (name == "arg_count") { + Vector<Variant> args = d_old["args"]; + args.resize(p_value); + d_new["args"] = args; + change_notify_deserved = true; + } else if (name.begins_with("args/")) { + Vector<Variant> args = d_old["args"]; + int idx = name.get_slice("/", 1).to_int(); + ERR_FAIL_INDEX_V(idx, args.size(), false); + + String what = name.get_slice("/", 2); + if (what == "type") { + Variant::Type t = Variant::Type(int(p_value)); + + if (t != args[idx].get_type()) { + Callable::CallError err; + if (Variant::can_convert(args[idx].get_type(), t)) { + Variant old = args[idx]; + Variant *ptrs[1] = { &old }; + Variant::construct(t, args.write[idx], (const Variant **)ptrs, 1, err); + } else { + Variant::construct(t, args.write[idx], nullptr, 0, err); + } + change_notify_deserved = true; + d_new["args"] = args; + } + } else if (what == "value") { + Variant value = p_value; + if (value.get_type() == Variant::NODE_PATH) { + _fix_node_path(value); + } - if (existing != -1) { - Variant v = animation->track_get_key_value(track, existing); - trans = animation->track_get_key_transition(track, existing); - undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, new_time, v, trans); + args.write[idx] = value; + d_new["args"] = args; + mergeable = true; + } } - undo_redo->commit_action(); - setting = false; - return true; - } + if (mergeable) { + undo_redo->create_action(TTR("Animation Change Call"), UndoRedo::MERGE_ENDS); + } else { + undo_redo->create_action(TTR("Animation Change Call")); + } - if (name == "easing") { - float val = p_value; - float prev_val = animation->track_get_key_transition(track, key); setting = true; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Animation Change Transition"), UndoRedo::MERGE_ENDS); - undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val); + undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old); undo_redo->add_do_method(this, "_update_obj", animation); undo_redo->add_undo_method(this, "_update_obj", animation); undo_redo->commit_action(); setting = false; + if (change_notify_deserved) { + notify_change(); + } return true; - } - - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - switch (animation->track_get_type(track)) { - case Animation::TYPE_POSITION_3D: - case Animation::TYPE_ROTATION_3D: - case Animation::TYPE_SCALE_3D: { - if (name == "position" || name == "rotation" || name == "scale") { - Variant old = animation->track_get_key_value(track, key); - setting = true; - String chan; - switch (animation->track_get_type(track)) { - case Animation::TYPE_POSITION_3D: - chan = "Position3D"; - break; - case Animation::TYPE_ROTATION_3D: - chan = "Rotation3D"; - break; - case Animation::TYPE_SCALE_3D: - chan = "Scale3D"; - break; - default: { - } - } - - undo_redo->create_action(vformat(TTR("Anim Change %s"), chan)); - undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); + } break; + case Animation::TYPE_BEZIER: { + if (name == "value") { + const Variant &value = p_value; - setting = false; - return true; - } + setting = true; + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); + float prev = animation->bezier_track_get_key_value(track, key); + undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); - } break; - case Animation::TYPE_BLEND_SHAPE: - case Animation::TYPE_VALUE: { - if (name == "value") { - Variant value = p_value; + setting = false; + return true; + } - if (value.get_type() == Variant::NODE_PATH) { - _fix_node_path(value); - } + if (name == "in_handle") { + const Variant &value = p_value; - setting = true; - undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - Variant prev = animation->track_get_key_value(track, key); - undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); + setting = true; + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); + Vector2 prev = animation->bezier_track_get_key_in_handle(track, key); + undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); - setting = false; - return true; - } - } break; - case Animation::TYPE_METHOD: { - Dictionary d_old = animation->track_get_key_value(track, key); - Dictionary d_new = d_old.duplicate(); + setting = false; + return true; + } - bool change_notify_deserved = false; - bool mergeable = false; + if (name == "out_handle") { + const Variant &value = p_value; - if (name == "name") { - d_new["method"] = p_value; - } else if (name == "arg_count") { - Vector<Variant> args = d_old["args"]; - args.resize(p_value); - d_new["args"] = args; - change_notify_deserved = true; - } else if (name.begins_with("args/")) { - Vector<Variant> args = d_old["args"]; - int idx = name.get_slice("/", 1).to_int(); - ERR_FAIL_INDEX_V(idx, args.size(), false); - - String what = name.get_slice("/", 2); - if (what == "type") { - Variant::Type t = Variant::Type(int(p_value)); - - if (t != args[idx].get_type()) { - Callable::CallError err; - if (Variant::can_convert(args[idx].get_type(), t)) { - Variant old = args[idx]; - Variant *ptrs[1] = { &old }; - Variant::construct(t, args.write[idx], (const Variant **)ptrs, 1, err); - } else { - Variant::construct(t, args.write[idx], nullptr, 0, err); - } - change_notify_deserved = true; - d_new["args"] = args; - } - } else if (what == "value") { - Variant value = p_value; - if (value.get_type() == Variant::NODE_PATH) { - _fix_node_path(value); - } + setting = true; + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); + Vector2 prev = animation->bezier_track_get_key_out_handle(track, key); + undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); - args.write[idx] = value; - d_new["args"] = args; - mergeable = true; - } - } + setting = false; + return true; + } - if (mergeable) { - undo_redo->create_action(TTR("Animation Change Call"), UndoRedo::MERGE_ENDS); - } else { - undo_redo->create_action(TTR("Animation Change Call")); - } + if (name == "handle_mode") { + const Variant &value = p_value; setting = true; - undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); + int prev = animation->bezier_track_get_key_handle_mode(track, key); + undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); + undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev); undo_redo->add_do_method(this, "_update_obj", animation); undo_redo->add_undo_method(this, "_update_obj", animation); undo_redo->commit_action(); setting = false; - if (change_notify_deserved) { - notify_change(); - } return true; - } break; - case Animation::TYPE_BEZIER: { - if (name == "value") { - const Variant &value = p_value; - - setting = true; - undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - float prev = animation->bezier_track_get_key_value(track, key); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); - - setting = false; - return true; - } + } + } break; + case Animation::TYPE_AUDIO: { + if (name == "stream") { + Ref<AudioStream> stream = p_value; - if (name == "in_handle") { - const Variant &value = p_value; + setting = true; + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); + Ref<Resource> prev = animation->audio_track_get_key_stream(track, key); + undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream); + undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); - setting = true; - undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - Vector2 prev = animation->bezier_track_get_key_in_handle(track, key); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); - - setting = false; - return true; - } + setting = false; + return true; + } - if (name == "out_handle") { - const Variant &value = p_value; + if (name == "start_offset") { + float value = p_value; - setting = true; - undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - Vector2 prev = animation->bezier_track_get_key_out_handle(track, key); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); - - setting = false; - return true; - } + setting = true; + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); + float prev = animation->audio_track_get_key_start_offset(track, key); + undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); - if (name == "handle_mode") { - const Variant &value = p_value; + setting = false; + return true; + } - setting = true; - undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - int prev = animation->bezier_track_get_key_handle_mode(track, key); - undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); - undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); - - setting = false; - return true; - } - } break; - case Animation::TYPE_AUDIO: { - if (name == "stream") { - Ref<AudioStream> stream = p_value; + if (name == "end_offset") { + float value = p_value; - setting = true; - undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - Ref<Resource> prev = animation->audio_track_get_key_stream(track, key); - undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream); - undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); - - setting = false; - return true; - } + setting = true; + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); + float prev = animation->audio_track_get_key_end_offset(track, key); + undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); - if (name == "start_offset") { - float value = p_value; + setting = false; + return true; + } + } break; + case Animation::TYPE_ANIMATION: { + if (name == "animation") { + StringName anim_name = p_value; - setting = true; - undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - float prev = animation->audio_track_get_key_start_offset(track, key); - undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); - - setting = false; - return true; - } + setting = true; + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); + StringName prev = animation->animation_track_get_key_animation(track, key); + undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name); + undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev); + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + undo_redo->commit_action(); - if (name == "end_offset") { - float value = p_value; + setting = false; + return true; + } + } break; + } - setting = true; - undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - float prev = animation->audio_track_get_key_end_offset(track, key); - undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); - - setting = false; - return true; - } - } break; - case Animation::TYPE_ANIMATION: { - if (name == "animation") { - StringName anim_name = p_value; + return false; +} - setting = true; - undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - StringName prev = animation->animation_track_get_key_animation(track, key); - undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name); - undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev); - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - undo_redo->commit_action(); - - setting = false; - return true; - } - } break; - } +bool AnimationTrackKeyEdit::_get(const StringName &p_name, Variant &r_ret) const { + int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX); + ERR_FAIL_COND_V(key == -1, false); - return false; + String name = p_name; + if (name == "easing") { + r_ret = animation->track_get_key_transition(track, key); + return true; } - bool _get(const StringName &p_name, Variant &r_ret) const { - int key = animation->track_find_key(track, key_ofs, true); - ERR_FAIL_COND_V(key == -1, false); - - String name = p_name; - if (name == "time") { - r_ret = key_ofs; - return true; - } - - if (name == "frame") { - float fps = animation->get_step(); - if (fps > 0) { - fps = 1.0 / fps; + switch (animation->track_get_type(track)) { + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { + if (name == "position" || name == "rotation" || name == "scale") { + r_ret = animation->track_get_key_value(track, key); + return true; + } + } break; + case Animation::TYPE_BLEND_SHAPE: + case Animation::TYPE_VALUE: { + if (name == "value") { + r_ret = animation->track_get_key_value(track, key); + return true; } - r_ret = key_ofs * fps; - return true; - } - if (name == "easing") { - r_ret = animation->track_get_key_transition(track, key); - return true; - } + } break; + case Animation::TYPE_METHOD: { + Dictionary d = animation->track_get_key_value(track, key); - switch (animation->track_get_type(track)) { - case Animation::TYPE_POSITION_3D: - case Animation::TYPE_ROTATION_3D: - case Animation::TYPE_SCALE_3D: { - if (name == "position" || name == "rotation" || name == "scale") { - r_ret = animation->track_get_key_value(track, key); - return true; - } - } break; - case Animation::TYPE_BLEND_SHAPE: - case Animation::TYPE_VALUE: { - if (name == "value") { - r_ret = animation->track_get_key_value(track, key); - return true; - } + if (name == "name") { + ERR_FAIL_COND_V(!d.has("method"), false); + r_ret = d["method"]; + return true; + } - } break; - case Animation::TYPE_METHOD: { - Dictionary d = animation->track_get_key_value(track, key); + ERR_FAIL_COND_V(!d.has("args"), false); - if (name == "name") { - ERR_FAIL_COND_V(!d.has("method"), false); - r_ret = d["method"]; - return true; - } + Vector<Variant> args = d["args"]; - ERR_FAIL_COND_V(!d.has("args"), false); + if (name == "arg_count") { + r_ret = args.size(); + return true; + } - Vector<Variant> args = d["args"]; + if (name.begins_with("args/")) { + int idx = name.get_slice("/", 1).to_int(); + ERR_FAIL_INDEX_V(idx, args.size(), false); - if (name == "arg_count") { - r_ret = args.size(); + String what = name.get_slice("/", 2); + if (what == "type") { + r_ret = args[idx].get_type(); return true; } - if (name.begins_with("args/")) { - int idx = name.get_slice("/", 1).to_int(); - ERR_FAIL_INDEX_V(idx, args.size(), false); - - String what = name.get_slice("/", 2); - if (what == "type") { - r_ret = args[idx].get_type(); - return true; - } - - if (what == "value") { - r_ret = args[idx]; - return true; - } - } - - } break; - case Animation::TYPE_BEZIER: { - if (name == "value") { - r_ret = animation->bezier_track_get_key_value(track, key); + if (what == "value") { + r_ret = args[idx]; return true; } + } - if (name == "in_handle") { - r_ret = animation->bezier_track_get_key_in_handle(track, key); - return true; - } + } break; + case Animation::TYPE_BEZIER: { + if (name == "value") { + r_ret = animation->bezier_track_get_key_value(track, key); + return true; + } - if (name == "out_handle") { - r_ret = animation->bezier_track_get_key_out_handle(track, key); - return true; - } + if (name == "in_handle") { + r_ret = animation->bezier_track_get_key_in_handle(track, key); + return true; + } - if (name == "handle_mode") { - r_ret = animation->bezier_track_get_key_handle_mode(track, key); - return true; - } + if (name == "out_handle") { + r_ret = animation->bezier_track_get_key_out_handle(track, key); + return true; + } - } break; - case Animation::TYPE_AUDIO: { - if (name == "stream") { - r_ret = animation->audio_track_get_key_stream(track, key); - return true; - } + if (name == "handle_mode") { + r_ret = animation->bezier_track_get_key_handle_mode(track, key); + return true; + } - if (name == "start_offset") { - r_ret = animation->audio_track_get_key_start_offset(track, key); - return true; - } + } break; + case Animation::TYPE_AUDIO: { + if (name == "stream") { + r_ret = animation->audio_track_get_key_stream(track, key); + return true; + } - if (name == "end_offset") { - r_ret = animation->audio_track_get_key_end_offset(track, key); - return true; - } + if (name == "start_offset") { + r_ret = animation->audio_track_get_key_start_offset(track, key); + return true; + } - } break; - case Animation::TYPE_ANIMATION: { - if (name == "animation") { - r_ret = animation->animation_track_get_key_animation(track, key); - return true; - } + if (name == "end_offset") { + r_ret = animation->audio_track_get_key_end_offset(track, key); + return true; + } - } break; - } + } break; + case Animation::TYPE_ANIMATION: { + if (name == "animation") { + r_ret = animation->animation_track_get_key_animation(track, key); + return true; + } - return false; + } break; } - void _get_property_list(List<PropertyInfo> *p_list) const { - if (animation.is_null()) { - return; - } - ERR_FAIL_INDEX(track, animation->get_track_count()); - int key = animation->track_find_key(track, key_ofs, true); - ERR_FAIL_COND(key == -1); + return false; +} - if (use_fps && animation->get_step() > 0) { - float max_frame = animation->get_length() / animation->get_step(); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("frame"), PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1")); - } else { - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("time"), PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01")); - } +void AnimationTrackKeyEdit::_get_property_list(List<PropertyInfo> *p_list) const { + if (animation.is_null()) { + return; + } - switch (animation->track_get_type(track)) { - case Animation::TYPE_POSITION_3D: { - p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("position"))); - } break; - case Animation::TYPE_ROTATION_3D: { - p_list->push_back(PropertyInfo(Variant::QUATERNION, PNAME("rotation"))); - } break; - case Animation::TYPE_SCALE_3D: { - p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("scale"))); - } break; - case Animation::TYPE_BLEND_SHAPE: { - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value"))); - } break; - case Animation::TYPE_VALUE: { - Variant v = animation->track_get_key_value(track, key); + ERR_FAIL_INDEX(track, animation->get_track_count()); + int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX); + ERR_FAIL_COND(key == -1); - if (hint.type != Variant::NIL) { - PropertyInfo pi = hint; - pi.name = PNAME("value"); - p_list->push_back(pi); - } else { - PropertyHint val_hint = PROPERTY_HINT_NONE; - String val_hint_string; - - if (v.get_type() == Variant::OBJECT) { - // Could actually check the object property if exists..? Yes I will! - Ref<Resource> res = v; - if (res.is_valid()) { - val_hint = PROPERTY_HINT_RESOURCE_TYPE; - val_hint_string = res->get_class(); - } - } + switch (animation->track_get_type(track)) { + case Animation::TYPE_POSITION_3D: { + p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("position"))); + } break; + case Animation::TYPE_ROTATION_3D: { + p_list->push_back(PropertyInfo(Variant::QUATERNION, PNAME("rotation"))); + } break; + case Animation::TYPE_SCALE_3D: { + p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("scale"))); + } break; + case Animation::TYPE_BLEND_SHAPE: { + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value"))); + } break; + case Animation::TYPE_VALUE: { + Variant v = animation->track_get_key_value(track, key); - if (v.get_type() != Variant::NIL) { - p_list->push_back(PropertyInfo(v.get_type(), PNAME("value"), val_hint, val_hint_string)); + if (hint.type != Variant::NIL) { + PropertyInfo pi = hint; + pi.name = PNAME("value"); + p_list->push_back(pi); + } else { + PropertyHint val_hint = PROPERTY_HINT_NONE; + String val_hint_string; + + if (v.get_type() == Variant::OBJECT) { + // Could actually check the object property if exists..? Yes I will! + Ref<Resource> res = v; + if (res.is_valid()) { + val_hint = PROPERTY_HINT_RESOURCE_TYPE; + val_hint_string = res->get_class(); } } - } break; - case Animation::TYPE_METHOD: { - p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("name"))); - p_list->push_back(PropertyInfo(Variant::INT, PNAME("arg_count"), PROPERTY_HINT_RANGE, "0,32,1,or_greater")); - - Dictionary d = animation->track_get_key_value(track, key); - ERR_FAIL_COND(!d.has("args")); - Vector<Variant> args = d["args"]; - String vtypes; - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i > 0) { - vtypes += ","; - } - vtypes += Variant::get_type_name(Variant::Type(i)); + if (v.get_type() != Variant::NIL) { + p_list->push_back(PropertyInfo(v.get_type(), PNAME("value"), val_hint, val_hint_string)); } + } - for (int i = 0; i < args.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%d/%s", PNAME("args"), i, PNAME("type")), PROPERTY_HINT_ENUM, vtypes)); - if (args[i].get_type() != Variant::NIL) { - p_list->push_back(PropertyInfo(args[i].get_type(), vformat("%s/%d/%s", PNAME("args"), i, PNAME("value")))); - } + } break; + case Animation::TYPE_METHOD: { + p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("name"))); + p_list->push_back(PropertyInfo(Variant::INT, PNAME("arg_count"), PROPERTY_HINT_RANGE, "0,32,1,or_greater")); + + Dictionary d = animation->track_get_key_value(track, key); + ERR_FAIL_COND(!d.has("args")); + Vector<Variant> args = d["args"]; + String vtypes; + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (i > 0) { + vtypes += ","; } + vtypes += Variant::get_type_name(Variant::Type(i)); + } - } break; - case Animation::TYPE_BEZIER: { - Animation::HandleMode hm = animation->bezier_track_get_key_handle_mode(track, key); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value"))); - if (hm == Animation::HANDLE_MODE_LINEAR) { - p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); - } else { - p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"))); - p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"))); + for (int i = 0; i < args.size(); i++) { + p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%d/%s", PNAME("args"), i, PNAME("type")), PROPERTY_HINT_ENUM, vtypes)); + if (args[i].get_type() != Variant::NIL) { + p_list->push_back(PropertyInfo(args[i].get_type(), vformat("%s/%d/%s", PNAME("args"), i, PNAME("value")))); } - p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored")); - - } break; - case Animation::TYPE_AUDIO: { - p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("stream"), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("start_offset"), PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("end_offset"), PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater")); + } - } break; - case Animation::TYPE_ANIMATION: { - String animations; + } break; + case Animation::TYPE_BEZIER: { + Animation::HandleMode hm = animation->bezier_track_get_key_handle_mode(track, key); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value"))); + if (hm == Animation::HANDLE_MODE_LINEAR) { + p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); + } else { + p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"))); + p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"))); + } + p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored")); - if (root_path && root_path->has_node(animation->track_get_path(track))) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node(animation->track_get_path(track))); - if (ap) { - List<StringName> anims; - ap->get_animation_list(&anims); - for (const StringName &E : anims) { - if (!animations.is_empty()) { - animations += ","; - } + } break; + case Animation::TYPE_AUDIO: { + p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("stream"), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("start_offset"), PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("end_offset"), PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater")); - animations += String(E); + } break; + case Animation::TYPE_ANIMATION: { + String animations; + + if (root_path && root_path->has_node(animation->track_get_path(track))) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node(animation->track_get_path(track))); + if (ap) { + List<StringName> anims; + ap->get_animation_list(&anims); + for (const StringName &E : anims) { + if (!animations.is_empty()) { + animations += ","; } + + animations += String(E); } } + } - if (!animations.is_empty()) { - animations += ","; - } - animations += "[stop]"; + if (!animations.is_empty()) { + animations += ","; + } + animations += "[stop]"; - p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("animation"), PROPERTY_HINT_ENUM, animations)); + p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("animation"), PROPERTY_HINT_ENUM, animations)); - } break; - } + } break; + } - if (animation->track_get_type(track) == Animation::TYPE_VALUE) { - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("easing"), PROPERTY_HINT_EXP_EASING)); - } + if (animation->track_get_type(track) == Animation::TYPE_VALUE) { + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("easing"), PROPERTY_HINT_EXP_EASING)); } +} - Ref<Animation> animation; - int track = -1; - float key_ofs = 0; - Node *root_path = nullptr; +void AnimationTrackKeyEdit::notify_change() { + notify_property_list_changed(); +} - PropertyInfo hint; - NodePath base; - bool use_fps = false; +Node *AnimationTrackKeyEdit::get_root_path() { + return root_path; +} - void notify_change() { - notify_property_list_changed(); - } +void AnimationTrackKeyEdit::set_use_fps(bool p_enable) { + use_fps = p_enable; + notify_property_list_changed(); +} - Node *get_root_path() { - return root_path; - } +void AnimationMultiTrackKeyEdit::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj); + ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed); + ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector); + ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_metadata_from_inspector); + ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path); + ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo); + ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only); +} - void set_use_fps(bool p_enable) { - use_fps = p_enable; - notify_property_list_changed(); +void AnimationMultiTrackKeyEdit::_fix_node_path(Variant &value, NodePath &base) { + NodePath np = value; + + if (np == NodePath()) { + return; } -}; -class AnimationMultiTrackKeyEdit : public Object { - GDCLASS(AnimationMultiTrackKeyEdit, Object); + Node *root = EditorNode::get_singleton()->get_tree()->get_root(); -public: - bool setting = false; - bool animation_read_only = false; + Node *np_node = root->get_node(np); + ERR_FAIL_COND(!np_node); - bool _hide_script_from_inspector() { return true; } - bool _hide_metadata_from_inspector() { return true; } - bool _dont_undo_redo() { return true; } + Node *edited_node = root->get_node(base); + ERR_FAIL_COND(!edited_node); - bool _is_read_only() { - return animation_read_only; - } + value = edited_node->get_path_to(np_node); +} - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj); - ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed); - ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector); - ClassDB::bind_method(D_METHOD("_hide_metadata_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_metadata_from_inspector); - ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path); - ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo); - ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only); +void AnimationMultiTrackKeyEdit::_update_obj(const Ref<Animation> &p_anim) { + if (setting || animation != p_anim) { + return; } - void _fix_node_path(Variant &value, NodePath &base) { - NodePath np = value; + notify_change(); +} - if (np == NodePath()) { - return; - } +void AnimationMultiTrackKeyEdit::_key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) { + if (animation != p_anim) { + return; + } - Node *root = EditorNode::get_singleton()->get_tree()->get_root(); + for (const KeyValue<int, List<float>> &E : key_ofs_map) { + int key = 0; + for (const float &key_ofs : E.value) { + if (from != key_ofs) { + key++; + continue; + } - Node *np_node = root->get_node(np); - ERR_FAIL_COND(!np_node); + int track = E.key; + key_ofs_map[track][key] = to; - Node *edited_node = root->get_node(base); - ERR_FAIL_COND(!edited_node); + if (setting) { + return; + } - value = edited_node->get_path_to(np_node); - } + notify_change(); - void _update_obj(const Ref<Animation> &p_anim) { - if (setting || animation != p_anim) { return; } - - notify_change(); } +} - void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) { - if (animation != p_anim) { - return; - } - - for (const KeyValue<int, List<float>> &E : key_ofs_map) { - int key = 0; - for (const float &key_ofs : E.value) { - if (from != key_ofs) { - key++; - continue; - } +bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p_value) { + bool update_obj = false; + bool change_notify_deserved = false; + for (const KeyValue<int, List<float>> &E : key_ofs_map) { + int track = E.key; + for (const float &key_ofs : E.value) { + int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX); + ERR_FAIL_COND_V(key == -1, false); - int track = E.key; - key_ofs_map[track][key] = to; + String name = p_name; + if (name == "easing") { + float val = p_value; + float prev_val = animation->track_get_key_transition(track, key); - if (setting) { - return; + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + if (!setting) { + setting = true; + undo_redo->create_action(TTR("Animation Multi Change Transition"), UndoRedo::MERGE_ENDS); } - - notify_change(); - - return; + undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val); + update_obj = true; } - } - } - bool _set(const StringName &p_name, const Variant &p_value) { - bool update_obj = false; - bool change_notify_deserved = false; - for (const KeyValue<int, List<float>> &E : key_ofs_map) { - int track = E.key; - for (const float &key_ofs : E.value) { - int key = animation->track_find_key(track, key_ofs, true); - ERR_FAIL_COND_V(key == -1, false); - - String name = p_name; - if (name == "time" || name == "frame") { - float new_time = p_value; - - if (name == "frame") { - float fps = animation->get_step(); - if (fps > 0) { - fps = 1.0 / fps; + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + switch (animation->track_get_type(track)) { + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { + Variant old = animation->track_get_key_value(track, key); + if (!setting) { + String chan; + switch (animation->track_get_type(track)) { + case Animation::TYPE_POSITION_3D: + chan = "Position3D"; + break; + case Animation::TYPE_ROTATION_3D: + chan = "Rotation3D"; + break; + case Animation::TYPE_SCALE_3D: + chan = "Scale3D"; + break; + default: { + } } - new_time /= fps; - } - - int existing = animation->track_find_key(track, new_time, true); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - if (!setting) { setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Time"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(vformat(TTR("Animation Multi Change %s"), chan)); } + undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old); + update_obj = true; + } break; + case Animation::TYPE_BLEND_SHAPE: + case Animation::TYPE_VALUE: { + if (name == "value") { + Variant value = p_value; - Variant val = animation->track_get_key_value(track, key); - float trans = animation->track_get_key_transition(track, key); - - undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key); - undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans); - undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time); - undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time); - undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans); - undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs); + if (value.get_type() == Variant::NODE_PATH) { + _fix_node_path(value, base_map[track]); + } - if (existing != -1) { - Variant v = animation->track_get_key_value(track, existing); - trans = animation->track_get_key_transition(track, existing); - undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, new_time, v, trans); + if (!setting) { + setting = true; + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + } + Variant prev = animation->track_get_key_value(track, key); + undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev); + update_obj = true; } - } else if (name == "easing") { - float val = p_value; - float prev_val = animation->track_get_key_transition(track, key); + } break; + case Animation::TYPE_METHOD: { + Dictionary d_old = animation->track_get_key_value(track, key); + Dictionary d_new = d_old.duplicate(); - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Transition"), UndoRedo::MERGE_ENDS); - } - undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val); - update_obj = true; - } + bool mergeable = false; - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - switch (animation->track_get_type(track)) { - case Animation::TYPE_POSITION_3D: - case Animation::TYPE_ROTATION_3D: - case Animation::TYPE_SCALE_3D: { - Variant old = animation->track_get_key_value(track, key); - if (!setting) { - String chan; - switch (animation->track_get_type(track)) { - case Animation::TYPE_POSITION_3D: - chan = "Position3D"; - break; - case Animation::TYPE_ROTATION_3D: - chan = "Rotation3D"; - break; - case Animation::TYPE_SCALE_3D: - chan = "Scale3D"; - break; - default: { + if (name == "name") { + d_new["method"] = p_value; + } else if (name == "arg_count") { + Vector<Variant> args = d_old["args"]; + args.resize(p_value); + d_new["args"] = args; + change_notify_deserved = true; + } else if (name.begins_with("args/")) { + Vector<Variant> args = d_old["args"]; + int idx = name.get_slice("/", 1).to_int(); + ERR_FAIL_INDEX_V(idx, args.size(), false); + + String what = name.get_slice("/", 2); + if (what == "type") { + Variant::Type t = Variant::Type(int(p_value)); + + if (t != args[idx].get_type()) { + Callable::CallError err; + if (Variant::can_convert(args[idx].get_type(), t)) { + Variant old = args[idx]; + Variant *ptrs[1] = { &old }; + Variant::construct(t, args.write[idx], (const Variant **)ptrs, 1, err); + } else { + Variant::construct(t, args.write[idx], nullptr, 0, err); } + change_notify_deserved = true; + d_new["args"] = args; } - - setting = true; - undo_redo->create_action(vformat(TTR("Animation Multi Change %s"), chan)); - } - undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old); - update_obj = true; - } break; - case Animation::TYPE_BLEND_SHAPE: - case Animation::TYPE_VALUE: { - if (name == "value") { + } else if (what == "value") { Variant value = p_value; - if (value.get_type() == Variant::NODE_PATH) { _fix_node_path(value, base_map[track]); } - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); - } - Variant prev = animation->track_get_key_value(track, key); - undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev); - update_obj = true; + args.write[idx] = value; + d_new["args"] = args; + mergeable = true; } - } break; - case Animation::TYPE_METHOD: { - Dictionary d_old = animation->track_get_key_value(track, key); - Dictionary d_new = d_old.duplicate(); + } - bool mergeable = false; + Variant prev = animation->track_get_key_value(track, key); - if (name == "name") { - d_new["method"] = p_value; - } else if (name == "arg_count") { - Vector<Variant> args = d_old["args"]; - args.resize(p_value); - d_new["args"] = args; - change_notify_deserved = true; - } else if (name.begins_with("args/")) { - Vector<Variant> args = d_old["args"]; - int idx = name.get_slice("/", 1).to_int(); - ERR_FAIL_INDEX_V(idx, args.size(), false); - - String what = name.get_slice("/", 2); - if (what == "type") { - Variant::Type t = Variant::Type(int(p_value)); - - if (t != args[idx].get_type()) { - Callable::CallError err; - if (Variant::can_convert(args[idx].get_type(), t)) { - Variant old = args[idx]; - Variant *ptrs[1] = { &old }; - Variant::construct(t, args.write[idx], (const Variant **)ptrs, 1, err); - } else { - Variant::construct(t, args.write[idx], nullptr, 0, err); - } - change_notify_deserved = true; - d_new["args"] = args; - } - } else if (what == "value") { - Variant value = p_value; - if (value.get_type() == Variant::NODE_PATH) { - _fix_node_path(value, base_map[track]); - } + if (!setting) { + if (mergeable) { + undo_redo->create_action(TTR("Animation Multi Change Call"), UndoRedo::MERGE_ENDS); + } else { + undo_redo->create_action(TTR("Animation Multi Change Call")); + } - args.write[idx] = value; - d_new["args"] = args; - mergeable = true; - } + setting = true; + } + + undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new); + undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old); + update_obj = true; + } break; + case Animation::TYPE_BEZIER: { + if (name == "value") { + const Variant &value = p_value; + + if (!setting) { + setting = true; + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } + float prev = animation->bezier_track_get_key_value(track, key); + undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev); + update_obj = true; + } else if (name == "in_handle") { + const Variant &value = p_value; - Variant prev = animation->track_get_key_value(track, key); + if (!setting) { + setting = true; + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + } + Vector2 prev = animation->bezier_track_get_key_in_handle(track, key); + undo_redo->add_do_method(this, "_bezier_track_set_key_in_handle", track, key, value); + undo_redo->add_undo_method(this, "_bezier_track_set_key_in_handle", track, key, prev); + update_obj = true; + } else if (name == "out_handle") { + const Variant &value = p_value; if (!setting) { - if (mergeable) { - undo_redo->create_action(TTR("Animation Multi Change Call"), UndoRedo::MERGE_ENDS); - } else { - undo_redo->create_action(TTR("Animation Multi Change Call")); - } + setting = true; + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + } + Vector2 prev = animation->bezier_track_get_key_out_handle(track, key); + undo_redo->add_do_method(this, "_bezier_track_set_key_out_handle", track, key, value); + undo_redo->add_undo_method(this, "_bezier_track_set_key_out_handle", track, key, prev); + update_obj = true; + } else if (name == "handle_mode") { + const Variant &value = p_value; + if (!setting) { setting = true; + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } + int prev = animation->bezier_track_get_key_handle_mode(track, key); + undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); + undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev); + update_obj = true; + } + } break; + case Animation::TYPE_AUDIO: { + if (name == "stream") { + Ref<AudioStream> stream = p_value; - undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new); - undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old); + if (!setting) { + setting = true; + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + } + Ref<Resource> prev = animation->audio_track_get_key_stream(track, key); + undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream); + undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev); update_obj = true; - } break; - case Animation::TYPE_BEZIER: { - if (name == "value") { - const Variant &value = p_value; + } else if (name == "start_offset") { + float value = p_value; - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); - } - float prev = animation->bezier_track_get_key_value(track, key); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev); - update_obj = true; - } else if (name == "in_handle") { - const Variant &value = p_value; - - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); - } - Vector2 prev = animation->bezier_track_get_key_in_handle(track, key); - undo_redo->add_do_method(this, "_bezier_track_set_key_in_handle", track, key, value); - undo_redo->add_undo_method(this, "_bezier_track_set_key_in_handle", track, key, prev); - update_obj = true; - } else if (name == "out_handle") { - const Variant &value = p_value; - - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); - } - Vector2 prev = animation->bezier_track_get_key_out_handle(track, key); - undo_redo->add_do_method(this, "_bezier_track_set_key_out_handle", track, key, value); - undo_redo->add_undo_method(this, "_bezier_track_set_key_out_handle", track, key, prev); - update_obj = true; - } else if (name == "handle_mode") { - const Variant &value = p_value; - - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); - } - int prev = animation->bezier_track_get_key_handle_mode(track, key); - undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); - undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev); - update_obj = true; + if (!setting) { + setting = true; + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } - } break; - case Animation::TYPE_AUDIO: { - if (name == "stream") { - Ref<AudioStream> stream = p_value; + float prev = animation->audio_track_get_key_start_offset(track, key); + undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev); + update_obj = true; + } else if (name == "end_offset") { + float value = p_value; - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); - } - Ref<Resource> prev = animation->audio_track_get_key_stream(track, key); - undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream); - undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev); - update_obj = true; - } else if (name == "start_offset") { - float value = p_value; - - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); - } - float prev = animation->audio_track_get_key_start_offset(track, key); - undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev); - update_obj = true; - } else if (name == "end_offset") { - float value = p_value; - - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); - } - float prev = animation->audio_track_get_key_end_offset(track, key); - undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value); - undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev); - update_obj = true; + if (!setting) { + setting = true; + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } - } break; - case Animation::TYPE_ANIMATION: { - if (name == "animation") { - StringName anim_name = p_value; + float prev = animation->audio_track_get_key_end_offset(track, key); + undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev); + update_obj = true; + } + } break; + case Animation::TYPE_ANIMATION: { + if (name == "animation") { + StringName anim_name = p_value; - if (!setting) { - setting = true; - undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); - } - StringName prev = animation->animation_track_get_key_animation(track, key); - undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name); - undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev); - update_obj = true; + if (!setting) { + setting = true; + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } - } break; - } + StringName prev = animation->animation_track_get_key_animation(track, key); + undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name); + undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev); + update_obj = true; + } + } break; } } + } - Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - if (setting) { - if (update_obj) { - undo_redo->add_do_method(this, "_update_obj", animation); - undo_redo->add_undo_method(this, "_update_obj", animation); - } - - undo_redo->commit_action(); - setting = false; + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + if (setting) { + if (update_obj) { + undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(this, "_update_obj", animation); + } - if (change_notify_deserved) { - notify_change(); - } + undo_redo->commit_action(); + setting = false; - return true; + if (change_notify_deserved) { + notify_change(); } - return false; + return true; } - bool _get(const StringName &p_name, Variant &r_ret) const { - for (const KeyValue<int, List<float>> &E : key_ofs_map) { - int track = E.key; - for (const float &key_ofs : E.value) { - int key = animation->track_find_key(track, key_ofs, true); - ERR_CONTINUE(key == -1); + return false; +} - String name = p_name; - if (name == "time") { - r_ret = key_ofs; - return true; - } +bool AnimationMultiTrackKeyEdit::_get(const StringName &p_name, Variant &r_ret) const { + for (const KeyValue<int, List<float>> &E : key_ofs_map) { + int track = E.key; + for (const float &key_ofs : E.value) { + int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX); + ERR_CONTINUE(key == -1); - if (name == "frame") { - float fps = animation->get_step(); - if (fps > 0) { - fps = 1.0 / fps; + String name = p_name; + if (name == "easing") { + r_ret = animation->track_get_key_transition(track, key); + return true; + } + + switch (animation->track_get_type(track)) { + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { + if (name == "position" || name == "rotation" || name == "scale") { + r_ret = animation->track_get_key_value(track, key); + return true; } - r_ret = key_ofs * fps; - return true; - } - if (name == "easing") { - r_ret = animation->track_get_key_transition(track, key); - return true; - } + } break; + case Animation::TYPE_BLEND_SHAPE: + case Animation::TYPE_VALUE: { + if (name == "value") { + r_ret = animation->track_get_key_value(track, key); + return true; + } - switch (animation->track_get_type(track)) { - case Animation::TYPE_POSITION_3D: - case Animation::TYPE_ROTATION_3D: - case Animation::TYPE_SCALE_3D: { - if (name == "position" || name == "rotation" || name == "scale") { - r_ret = animation->track_get_key_value(track, key); - return true; - } + } break; + case Animation::TYPE_METHOD: { + Dictionary d = animation->track_get_key_value(track, key); - } break; - case Animation::TYPE_BLEND_SHAPE: - case Animation::TYPE_VALUE: { - if (name == "value") { - r_ret = animation->track_get_key_value(track, key); - return true; - } + if (name == "name") { + ERR_FAIL_COND_V(!d.has("method"), false); + r_ret = d["method"]; + return true; + } - } break; - case Animation::TYPE_METHOD: { - Dictionary d = animation->track_get_key_value(track, key); + ERR_FAIL_COND_V(!d.has("args"), false); - if (name == "name") { - ERR_FAIL_COND_V(!d.has("method"), false); - r_ret = d["method"]; - return true; - } + Vector<Variant> args = d["args"]; - ERR_FAIL_COND_V(!d.has("args"), false); + if (name == "arg_count") { + r_ret = args.size(); + return true; + } - Vector<Variant> args = d["args"]; + if (name.begins_with("args/")) { + int idx = name.get_slice("/", 1).to_int(); + ERR_FAIL_INDEX_V(idx, args.size(), false); - if (name == "arg_count") { - r_ret = args.size(); + String what = name.get_slice("/", 2); + if (what == "type") { + r_ret = args[idx].get_type(); return true; } - if (name.begins_with("args/")) { - int idx = name.get_slice("/", 1).to_int(); - ERR_FAIL_INDEX_V(idx, args.size(), false); - - String what = name.get_slice("/", 2); - if (what == "type") { - r_ret = args[idx].get_type(); - return true; - } - - if (what == "value") { - r_ret = args[idx]; - return true; - } - } - - } break; - case Animation::TYPE_BEZIER: { - if (name == "value") { - r_ret = animation->bezier_track_get_key_value(track, key); + if (what == "value") { + r_ret = args[idx]; return true; } + } - if (name == "in_handle") { - r_ret = animation->bezier_track_get_key_in_handle(track, key); - return true; - } + } break; + case Animation::TYPE_BEZIER: { + if (name == "value") { + r_ret = animation->bezier_track_get_key_value(track, key); + return true; + } - if (name == "out_handle") { - r_ret = animation->bezier_track_get_key_out_handle(track, key); - return true; - } + if (name == "in_handle") { + r_ret = animation->bezier_track_get_key_in_handle(track, key); + return true; + } - if (name == "handle_mode") { - r_ret = animation->bezier_track_get_key_handle_mode(track, key); - return true; - } + if (name == "out_handle") { + r_ret = animation->bezier_track_get_key_out_handle(track, key); + return true; + } - } break; - case Animation::TYPE_AUDIO: { - if (name == "stream") { - r_ret = animation->audio_track_get_key_stream(track, key); - return true; - } + if (name == "handle_mode") { + r_ret = animation->bezier_track_get_key_handle_mode(track, key); + return true; + } - if (name == "start_offset") { - r_ret = animation->audio_track_get_key_start_offset(track, key); - return true; - } + } break; + case Animation::TYPE_AUDIO: { + if (name == "stream") { + r_ret = animation->audio_track_get_key_stream(track, key); + return true; + } - if (name == "end_offset") { - r_ret = animation->audio_track_get_key_end_offset(track, key); - return true; - } + if (name == "start_offset") { + r_ret = animation->audio_track_get_key_start_offset(track, key); + return true; + } - } break; - case Animation::TYPE_ANIMATION: { - if (name == "animation") { - r_ret = animation->animation_track_get_key_animation(track, key); - return true; - } + if (name == "end_offset") { + r_ret = animation->audio_track_get_key_end_offset(track, key); + return true; + } - } break; - } + } break; + case Animation::TYPE_ANIMATION: { + if (name == "animation") { + r_ret = animation->animation_track_get_key_animation(track, key); + return true; + } + + } break; } } + } - return false; + return false; +} + +void AnimationMultiTrackKeyEdit::_get_property_list(List<PropertyInfo> *p_list) const { + if (animation.is_null()) { + return; } - void _get_property_list(List<PropertyInfo> *p_list) const { - if (animation.is_null()) { - return; - } - int first_track = -1; - float first_key = -1.0; + int first_track = -1; + float first_key = -1.0; - bool show_time = true; - bool same_track_type = true; - bool same_key_type = true; - for (const KeyValue<int, List<float>> &E : key_ofs_map) { - int track = E.key; - ERR_FAIL_INDEX(track, animation->get_track_count()); + bool same_track_type = true; + bool same_key_type = true; + for (const KeyValue<int, List<float>> &E : key_ofs_map) { + int track = E.key; + ERR_FAIL_INDEX(track, animation->get_track_count()); - if (first_track < 0) { - first_track = track; - } + if (first_track < 0) { + first_track = track; + } - if (show_time && E.value.size() > 1) { - show_time = false; + if (same_track_type) { + if (animation->track_get_type(first_track) != animation->track_get_type(track)) { + same_track_type = false; + same_key_type = false; } - if (same_track_type) { - if (animation->track_get_type(first_track) != animation->track_get_type(track)) { - same_track_type = false; - same_key_type = false; + for (const float &F : E.value) { + int key = animation->track_find_key(track, F, Animation::FIND_MODE_APPROX); + ERR_FAIL_COND(key == -1); + if (first_key < 0) { + first_key = key; } - for (const float &F : E.value) { - int key = animation->track_find_key(track, F, true); - ERR_FAIL_COND(key == -1); - if (first_key < 0) { - first_key = key; - } - - if (animation->track_get_key_value(first_track, first_key).get_type() != animation->track_get_key_value(track, key).get_type()) { - same_key_type = false; - } + if (animation->track_get_key_value(first_track, first_key).get_type() != animation->track_get_key_value(track, key).get_type()) { + same_key_type = false; } } } + } - if (show_time) { - if (use_fps && animation->get_step() > 0) { - float max_frame = animation->get_length() / animation->get_step(); - p_list->push_back(PropertyInfo(Variant::FLOAT, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1")); - } else { - p_list->push_back(PropertyInfo(Variant::FLOAT, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01")); - } - } - - if (same_track_type) { - switch (animation->track_get_type(first_track)) { - case Animation::TYPE_POSITION_3D: { - p_list->push_back(PropertyInfo(Variant::VECTOR3, "position")); - } break; - case Animation::TYPE_ROTATION_3D: { - p_list->push_back(PropertyInfo(Variant::QUATERNION, "scale")); - } break; - case Animation::TYPE_SCALE_3D: { - p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale")); - } break; - case Animation::TYPE_BLEND_SHAPE: { - p_list->push_back(PropertyInfo(Variant::FLOAT, "value")); - } break; - case Animation::TYPE_VALUE: { - if (same_key_type) { - Variant v = animation->track_get_key_value(first_track, first_key); + if (same_track_type) { + switch (animation->track_get_type(first_track)) { + case Animation::TYPE_POSITION_3D: { + p_list->push_back(PropertyInfo(Variant::VECTOR3, "position")); + } break; + case Animation::TYPE_ROTATION_3D: { + p_list->push_back(PropertyInfo(Variant::QUATERNION, "scale")); + } break; + case Animation::TYPE_SCALE_3D: { + p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale")); + } break; + case Animation::TYPE_BLEND_SHAPE: { + p_list->push_back(PropertyInfo(Variant::FLOAT, "value")); + } break; + case Animation::TYPE_VALUE: { + if (same_key_type) { + Variant v = animation->track_get_key_value(first_track, first_key); - if (hint.type != Variant::NIL) { - PropertyInfo pi = hint; - pi.name = "value"; - p_list->push_back(pi); - } else { - PropertyHint val_hint = PROPERTY_HINT_NONE; - String val_hint_string; - - if (v.get_type() == Variant::OBJECT) { - // Could actually check the object property if exists..? Yes I will! - Ref<Resource> res = v; - if (res.is_valid()) { - val_hint = PROPERTY_HINT_RESOURCE_TYPE; - val_hint_string = res->get_class(); - } + if (hint.type != Variant::NIL) { + PropertyInfo pi = hint; + pi.name = "value"; + p_list->push_back(pi); + } else { + PropertyHint val_hint = PROPERTY_HINT_NONE; + String val_hint_string; + + if (v.get_type() == Variant::OBJECT) { + // Could actually check the object property if exists..? Yes I will! + Ref<Resource> res = v; + if (res.is_valid()) { + val_hint = PROPERTY_HINT_RESOURCE_TYPE; + val_hint_string = res->get_class(); } + } - if (v.get_type() != Variant::NIL) { - p_list->push_back(PropertyInfo(v.get_type(), "value", val_hint, val_hint_string)); - } + if (v.get_type() != Variant::NIL) { + p_list->push_back(PropertyInfo(v.get_type(), "value", val_hint, val_hint_string)); } } + } - p_list->push_back(PropertyInfo(Variant::FLOAT, "easing", PROPERTY_HINT_EXP_EASING)); - } break; - case Animation::TYPE_METHOD: { - p_list->push_back(PropertyInfo(Variant::STRING_NAME, "name")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "easing", PROPERTY_HINT_EXP_EASING)); + } break; + case Animation::TYPE_METHOD: { + p_list->push_back(PropertyInfo(Variant::STRING_NAME, "name")); - p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,32,1,or_greater")); + p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,32,1,or_greater")); - Dictionary d = animation->track_get_key_value(first_track, first_key); - ERR_FAIL_COND(!d.has("args")); - Vector<Variant> args = d["args"]; - String vtypes; - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - if (i > 0) { - vtypes += ","; - } - vtypes += Variant::get_type_name(Variant::Type(i)); + Dictionary d = animation->track_get_key_value(first_track, first_key); + ERR_FAIL_COND(!d.has("args")); + Vector<Variant> args = d["args"]; + String vtypes; + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (i > 0) { + vtypes += ","; } + vtypes += Variant::get_type_name(Variant::Type(i)); + } - for (int i = 0; i < args.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, "args/" + itos(i) + "/type", PROPERTY_HINT_ENUM, vtypes)); - if (args[i].get_type() != Variant::NIL) { - p_list->push_back(PropertyInfo(args[i].get_type(), "args/" + itos(i) + "/value")); - } - } - } break; - case Animation::TYPE_BEZIER: { - p_list->push_back(PropertyInfo(Variant::FLOAT, "value")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle")); - p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored")); - } break; - case Animation::TYPE_AUDIO: { - p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream")); - p_list->push_back(PropertyInfo(Variant::FLOAT, "start_offset", PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater")); - p_list->push_back(PropertyInfo(Variant::FLOAT, "end_offset", PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater")); - } break; - case Animation::TYPE_ANIMATION: { - if (key_ofs_map.size() > 1) { - break; + for (int i = 0; i < args.size(); i++) { + p_list->push_back(PropertyInfo(Variant::INT, "args/" + itos(i) + "/type", PROPERTY_HINT_ENUM, vtypes)); + if (args[i].get_type() != Variant::NIL) { + p_list->push_back(PropertyInfo(args[i].get_type(), "args/" + itos(i) + "/value")); } + } + } break; + case Animation::TYPE_BEZIER: { + p_list->push_back(PropertyInfo(Variant::FLOAT, "value")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle")); + p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored")); + } break; + case Animation::TYPE_AUDIO: { + p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "start_offset", PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "end_offset", PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater")); + } break; + case Animation::TYPE_ANIMATION: { + if (key_ofs_map.size() > 1) { + break; + } - String animations; - - if (root_path && root_path->has_node(animation->track_get_path(first_track))) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node(animation->track_get_path(first_track))); - if (ap) { - List<StringName> anims; - ap->get_animation_list(&anims); - for (List<StringName>::Element *G = anims.front(); G; G = G->next()) { - if (!animations.is_empty()) { - animations += ","; - } + String animations; - animations += String(G->get()); + if (root_path && root_path->has_node(animation->track_get_path(first_track))) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node(animation->track_get_path(first_track))); + if (ap) { + List<StringName> anims; + ap->get_animation_list(&anims); + for (List<StringName>::Element *G = anims.front(); G; G = G->next()) { + if (!animations.is_empty()) { + animations += ","; } + + animations += String(G->get()); } } + } - if (!animations.is_empty()) { - animations += ","; - } - animations += "[stop]"; + if (!animations.is_empty()) { + animations += ","; + } + animations += "[stop]"; - p_list->push_back(PropertyInfo(Variant::STRING_NAME, "animation", PROPERTY_HINT_ENUM, animations)); - } break; - } + p_list->push_back(PropertyInfo(Variant::STRING_NAME, "animation", PROPERTY_HINT_ENUM, animations)); + } break; } } +} - Ref<Animation> animation; - - RBMap<int, List<float>> key_ofs_map; - RBMap<int, NodePath> base_map; - PropertyInfo hint; - - Node *root_path = nullptr; - - bool use_fps = false; - - void notify_change() { - notify_property_list_changed(); - } +void AnimationMultiTrackKeyEdit::notify_change() { + notify_property_list_changed(); +} - Node *get_root_path() { - return root_path; - } +Node *AnimationMultiTrackKeyEdit::get_root_path() { + return root_path; +} - void set_use_fps(bool p_enable) { - use_fps = p_enable; - notify_property_list_changed(); - } -}; +void AnimationMultiTrackKeyEdit::set_use_fps(bool p_enable) { + use_fps = p_enable; + notify_property_list_changed(); +} void AnimationTimelineEdit::_zoom_changed(double) { queue_redraw(); @@ -1420,7 +1246,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) { return; } - p_new_len = MAX(0.001, p_new_len); + p_new_len = MAX(0.0001, p_new_len); if (use_fps && animation->get_step() > 0) { p_new_len *= animation->get_step(); } @@ -1539,7 +1365,7 @@ void AnimationTimelineEdit::_notification(int p_what) { float l = animation->get_length(); if (l <= 0) { - l = 0.001; // Avoid crashor. + l = 0.0001; // Avoid crashor. } Ref<Texture2D> hsize_icon = get_theme_icon(SNAME("Hsize"), SNAME("EditorIcons")); @@ -1600,7 +1426,7 @@ void AnimationTimelineEdit::_notification(int p_what) { end_px = zoomw; } - draw_rect(Rect2(Point2(get_name_limit() + begin_px, 0), Point2(end_px - begin_px - 1, h)), timecolor); + draw_rect(Rect2(Point2(get_name_limit() + begin_px, 0), Point2(end_px - begin_px, h)), timecolor); } } @@ -1759,7 +1585,7 @@ void AnimationTimelineEdit::update_values() { } } else { length->set_value(animation->get_length()); - length->set_step(0.001); + length->set_step(0.0001); length->set_tooltip_text(TTR("Animation length (seconds)")); time_icon->set_tooltip_text(TTR("Animation length (seconds)")); } @@ -1950,9 +1776,9 @@ AnimationTimelineEdit::AnimationTimelineEdit() { time_icon->set_tooltip_text(TTR("Animation length (seconds)")); len_hb->add_child(time_icon); length = memnew(EditorSpinSlider); - length->set_min(0.001); + length->set_min(0.0001); length->set_max(36000); - length->set_step(0.001); + length->set_step(0.0001); length->set_allow_greater(true); length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0)); length->set_hide_slider(true); @@ -2058,7 +1884,7 @@ void AnimationTrackEdit::_notification(int p_what) { } else if (animation->track_get_type(track) == Animation::TYPE_AUDIO) { text = TTR("Audio Clips:"); } else if (animation->track_get_type(track) == Animation::TYPE_ANIMATION) { - text = TTR("Anim Clips:"); + text = TTR("Animation Clips:"); } else { text += anim_path.get_concatenated_subnames(); } @@ -2670,7 +2496,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { } if (key_idx != -1) { - String text = TTR("Time (s):") + " " + rtos(animation->track_get_key_time(track, key_idx)) + "\n"; + String text = TTR("Time (s):") + " " + TS->format_number(rtos(Math::snapped(animation->track_get_key_time(track, key_idx), 0.0001))) + "\n"; switch (animation->track_get_type(track)) { case Animation::TYPE_POSITION_3D: { Vector3 t = animation->track_get_key_value(track, key_idx); @@ -4390,7 +4216,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD p_next_tracks.normal++; } else { undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_id.track_idx, time); - int existing = animation->track_find_key(p_id.track_idx, time, true); + int existing = animation->track_find_key(p_id.track_idx, time, Animation::FIND_MODE_APPROX); if (existing != -1) { Variant v = animation->track_get_key_value(p_id.track_idx, existing); float trans = animation->track_get_key_transition(p_id.track_idx, existing); @@ -5005,8 +4831,8 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { if (snap->is_pressed() && step->get_value() != 0) { p_ofs = snap_time(p_ofs); } - while (animation->track_find_key(p_track, p_ofs, true) != -1) { // Make sure insertion point is valid. - p_ofs += 0.001; + while (animation->track_find_key(p_track, p_ofs, Animation::FIND_MODE_APPROX) != -1) { // Make sure insertion point is valid. + p_ofs += 0.0001; } Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); @@ -5338,7 +5164,7 @@ void AnimationTrackEditor::_select_at_anim(const Ref<Animation> &p_anim, int p_t return; } - int idx = animation->track_find_key(p_track, p_pos, true); + int idx = animation->track_find_key(p_track, p_pos, Animation::FIND_MODE_APPROX); ERR_FAIL_COND(idx < 0); SelectedKey sk; @@ -5365,7 +5191,7 @@ void AnimationTrackEditor::_move_selection_commit() { // 2 - Remove overlapped keys. for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float newtime = snap_time(E->get().pos + motion); - int idx = animation->track_find_key(E->key().track, newtime, true); + int idx = animation->track_find_key(E->key().track, newtime, Animation::FIND_MODE_APPROX); if (idx == -1) { continue; } @@ -5625,7 +5451,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { continue; } - int existing_idx = animation->track_find_key(dst_track, dst_time, true); + int existing_idx = animation->track_find_key(dst_track, dst_time, Animation::FIND_MODE_APPROX); undo_redo->add_do_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key)); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", dst_track, dst_time); @@ -5916,7 +5742,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { // 2 - Remove overlapped keys. for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float newtime = (E->get().pos - from_t) * s + from_t; - int idx = animation->track_find_key(E->key().track, newtime, true); + int idx = animation->track_find_key(E->key().track, newtime, Animation::FIND_MODE_APPROX); if (idx == -1) { continue; } @@ -6127,7 +5953,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { undo_redo->add_do_method(reset.ptr(), "track_set_path", dst_track, path); undo_redo->add_undo_method(reset.ptr(), "remove_track", dst_track); } else { - existing_idx = reset->track_find_key(dst_track, 0, true); + existing_idx = reset->track_find_key(dst_track, 0, Animation::FIND_MODE_APPROX); } undo_redo->add_do_method(reset.ptr(), "track_insert_key", dst_track, 0, animation->track_get_key_value(sk.track, sk.key), animation->track_get_key_transition(sk.track, sk.key)); @@ -6656,7 +6482,7 @@ AnimationTrackEditor::AnimationTrackEditor() { step = memnew(EditorSpinSlider); step->set_min(0); step->set_max(1000000); - step->set_step(0.001); + step->set_step(0.0001); step->set_hide_slider(true); step->set_custom_minimum_size(Size2(100, 0) * EDSCALE); step->set_tooltip_text(TTR("Animation step value.")); @@ -6946,3 +6772,103 @@ AnimationTrackEditor::~AnimationTrackEditor() { memdelete(multi_key_edit); } } + +// AnimationTrackKeyEditEditorPlugin + +void AnimationTrackKeyEditEditor::_time_edit_entered() { + int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX); + if (key == -1) { + return; + } + key_data_cache.time = animation->track_get_key_time(track, key); + key_data_cache.transition = animation->track_get_key_transition(track, key); + key_data_cache.value = animation->track_get_key_value(track, key); +} + +void AnimationTrackKeyEditEditor::_time_edit_exited() { + real_t new_time = spinner->get_value(); + + if (use_fps) { + real_t fps = animation->get_step(); + if (fps > 0) { + fps = 1.0 / fps; + } + new_time /= fps; + } + + if (Math::is_equal_approx(new_time, key_data_cache.time)) { + return; // No change. + } + + int existing = animation->track_find_key(track, new_time, Animation::FIND_MODE_APPROX); + Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); + undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS); + + if (existing != -1) { + undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, animation->track_get_key_time(track, existing)); + } + undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, key_data_cache.time); + undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, key_data_cache.value, key_data_cache.transition); + undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time); + undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_data_cache.time, key_data_cache.value, key_data_cache.transition); + if (existing != -1) { + undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, animation->track_get_key_time(track, existing), animation->track_get_key_value(track, existing), animation->track_get_key_transition(track, existing)); + } + + // Reselect key. + AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton(); + if (ape) { + AnimationTrackEditor *ate = ape->get_track_editor(); + if (ate) { + undo_redo->add_do_method(ate, "_clear_selection_for_anim", animation); + undo_redo->add_undo_method(ate, "_clear_selection_for_anim", animation); + undo_redo->add_do_method(ate, "_select_at_anim", animation, track, new_time); + undo_redo->add_undo_method(ate, "_select_at_anim", animation, track, key_data_cache.time); + } + } + + undo_redo->commit_action(); +} + +AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref<Animation> p_animation, int p_track, real_t p_key_ofs, bool p_use_fps) { + if (!p_animation.is_valid()) { + return; + } + + animation = p_animation; + track = p_track; + key_ofs = p_key_ofs; + use_fps = p_use_fps; + + set_label("Time"); + + spinner = memnew(EditorSpinSlider); + spinner->set_focus_mode(Control::FOCUS_CLICK); + spinner->set_min(0); + spinner->set_allow_greater(true); + spinner->set_allow_lesser(true); + + if (use_fps) { + spinner->set_step(1); + spinner->set_hide_slider(true); + real_t fps = animation->get_step(); + if (fps > 0) { + fps = 1.0 / fps; + } + spinner->set_value(key_ofs * fps); + } else { + spinner->set_step(0.0001); + spinner->set_value(key_ofs); + spinner->set_max(animation->get_length()); + } + + add_child(spinner); + + spinner->connect("grabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED); + spinner->connect("ungrabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED); + spinner->connect("value_focus_entered", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED); + spinner->connect("value_focus_exited", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED); +} + +AnimationTrackKeyEditEditor::~AnimationTrackKeyEditEditor() { +} diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 4b50424f39..5ae826bd5c 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -50,9 +50,83 @@ #include "scene/resources/animation.h" #include "scene_tree_editor.h" +class AnimationTrackEditor; class AnimationTrackEdit; class ViewPanner; +class AnimationTrackKeyEdit : public Object { + GDCLASS(AnimationTrackKeyEdit, Object); + +public: + bool setting = false; + bool animation_read_only = false; + + Ref<Animation> animation; + int track = -1; + float key_ofs = 0; + Node *root_path = nullptr; + + PropertyInfo hint; + NodePath base; + bool use_fps = false; + + bool _hide_script_from_inspector() { return true; } + bool _hide_metadata_from_inspector() { return true; } + bool _dont_undo_redo() { return true; } + + bool _is_read_only() { return animation_read_only; } + + void notify_change(); + Node *get_root_path(); + void set_use_fps(bool p_enable); + +protected: + static void _bind_methods(); + void _fix_node_path(Variant &value); + void _update_obj(const Ref<Animation> &p_anim); + void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; +}; + +class AnimationMultiTrackKeyEdit : public Object { + GDCLASS(AnimationMultiTrackKeyEdit, Object); + +public: + bool setting = false; + bool animation_read_only = false; + + Ref<Animation> animation; + + RBMap<int, List<float>> key_ofs_map; + RBMap<int, NodePath> base_map; + PropertyInfo hint; + + Node *root_path = nullptr; + + bool use_fps = false; + + bool _hide_script_from_inspector() { return true; } + bool _hide_metadata_from_inspector() { return true; } + bool _dont_undo_redo() { return true; } + + bool _is_read_only() { return animation_read_only; } + + void notify_change(); + Node *get_root_path(); + void set_use_fps(bool p_enable); + +protected: + static void _bind_methods(); + void _fix_node_path(Variant &value, NodePath &base); + void _update_obj(const Ref<Animation> &p_anim); + void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; +}; + class AnimationTimelineEdit : public Range { GDCLASS(AnimationTimelineEdit, Range); @@ -129,8 +203,6 @@ public: AnimationTimelineEdit(); }; -class AnimationTrackEditor; - class AnimationTrackEdit : public Control { GDCLASS(AnimationTrackEdit, Control); friend class AnimationTimelineEdit; @@ -592,4 +664,30 @@ public: ~AnimationTrackEditor(); }; +// AnimationTrackKeyEditEditorPlugin + +class AnimationTrackKeyEditEditor : public EditorProperty { + GDCLASS(AnimationTrackKeyEditEditor, EditorProperty); + + Ref<Animation> animation; + int track = -1; + real_t key_ofs = 0.0; + bool use_fps = false; + + EditorSpinSlider *spinner = nullptr; + + struct KeyDataCache { + real_t time = 0.0; + float transition = 0.0; + Variant value; + } key_data_cache; + + void _time_edit_entered(); + void _time_edit_exited(); + +public: + AnimationTrackKeyEditEditor(Ref<Animation> p_animation, int p_track, real_t p_key_ofs, bool p_use_fps); + ~AnimationTrackKeyEditEditor(); +}; + #endif // ANIMATION_TRACK_EDITOR_H diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index 704935e163..0ad62710eb 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -831,8 +831,8 @@ Rect2 AnimationTrackEditTypeAudio::get_key_rect(int p_index, float p_pixels_sec) len -= end_ofs; len -= start_ofs; - if (len <= 0.001) { - len = 0.001; + if (len <= 0.0001) { + len = 0.0001; } if (get_animation()->track_get_key_count(get_track()) > p_index + 1) { @@ -887,8 +887,8 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int len -= end_ofs; len -= start_ofs; - if (len <= 0.001) { - len = 0.001; + if (len <= 0.0001) { + len = 0.0001; } int pixel_len = len * p_pixels_sec; @@ -1014,8 +1014,8 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant ofs = get_editor()->snap_time(ofs); - while (get_animation()->track_find_key(get_track(), ofs, true) != -1) { //make sure insertion point is valid - ofs += 0.001; + while (get_animation()->track_find_key(get_track(), ofs, Animation::FIND_MODE_APPROX) != -1) { //make sure insertion point is valid + ofs += 0.0001; } Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp index 35666a5566..0f8b2f36be 100644 --- a/editor/debugger/editor_profiler.cpp +++ b/editor/debugger/editor_profiler.cpp @@ -106,7 +106,7 @@ void EditorProfiler::clear() { seeking = false; // Ensure button text (start, stop) is correct - _set_button_text(); + _update_button_text(); emit_signal(SNAME("enable_profiling"), activate->is_pressed()); } @@ -376,7 +376,7 @@ void EditorProfiler::_update_frame() { updating_frame = false; } -void EditorProfiler::_set_button_text() { +void EditorProfiler::_update_button_text() { if (activate->is_pressed()) { activate->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); activate->set_text(TTR("Stop")); @@ -387,7 +387,7 @@ void EditorProfiler::_set_button_text() { } void EditorProfiler::_activate_pressed() { - _set_button_text(); + _update_button_text(); if (activate->is_pressed()) { _clear_pressed(); @@ -510,13 +510,17 @@ void EditorProfiler::_bind_methods() { } void EditorProfiler::set_enabled(bool p_enable, bool p_clear) { - activate->set_pressed(false); activate->set_disabled(!p_enable); if (p_clear) { clear(); } } +void EditorProfiler::set_pressed(bool p_pressed) { + activate->set_pressed(p_pressed); + _update_button_text(); +} + bool EditorProfiler::is_profiling() { return activate->is_pressed(); } @@ -595,6 +599,7 @@ EditorProfiler::EditorProfiler() { add_child(hb); activate = memnew(Button); activate->set_toggle_mode(true); + activate->set_disabled(true); activate->set_text(TTR("Start")); activate->connect("pressed", callable_mp(this, &EditorProfiler::_activate_pressed)); hb->add_child(activate); diff --git a/editor/debugger/editor_profiler.h b/editor/debugger/editor_profiler.h index e9ecc285ed..d0dd67688b 100644 --- a/editor/debugger/editor_profiler.h +++ b/editor/debugger/editor_profiler.h @@ -122,7 +122,7 @@ private: Timer *frame_delay = nullptr; Timer *plot_delay = nullptr; - void _set_button_text(); + void _update_button_text(); void _update_frame(); void _activate_pressed(); @@ -155,6 +155,7 @@ protected: public: void add_frame_metric(const Metric &p_metric, bool p_final = false); void set_enabled(bool p_enable, bool p_clear = true); + void set_pressed(bool p_pressed); bool is_profiling(); bool is_seeking() { return seeking; } void disable_seeking(); diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp index b8bc712ba6..fe425220c9 100644 --- a/editor/debugger/editor_visual_profiler.cpp +++ b/editor/debugger/editor_visual_profiler.cpp @@ -66,6 +66,7 @@ void EditorVisualProfiler::add_frame_metric(const Metric &p_metric) { } updating_frame = true; + clear_button->set_disabled(false); cursor_metric_edit->set_max(frame_metrics[last_metric].frame_number); cursor_metric_edit->set_min(MAX(frame_metrics[last_metric].frame_number - frame_metrics.size(), 0u)); @@ -408,6 +409,7 @@ void EditorVisualProfiler::_activate_pressed() { activate->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); activate->set_text(TTR("Stop")); _clear_pressed(); //always clear on start + clear_button->set_disabled(false); } else { activate->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons"))); activate->set_text(TTR("Start")); @@ -416,6 +418,7 @@ void EditorVisualProfiler::_activate_pressed() { } void EditorVisualProfiler::_clear_pressed() { + clear_button->set_disabled(true); clear(); _update_plot(); } @@ -647,10 +650,25 @@ void EditorVisualProfiler::_bind_methods() { ADD_SIGNAL(MethodInfo("enable_profiling", PropertyInfo(Variant::BOOL, "enable"))); } +void EditorVisualProfiler::_update_button_text() { + if (activate->is_pressed()) { + activate->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); + activate->set_text(TTR("Stop")); + } else { + activate->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons"))); + activate->set_text(TTR("Start")); + } +} + void EditorVisualProfiler::set_enabled(bool p_enable) { activate->set_disabled(!p_enable); } +void EditorVisualProfiler::set_pressed(bool p_pressed) { + activate->set_pressed(p_pressed); + _update_button_text(); +} + bool EditorVisualProfiler::is_profiling() { return activate->is_pressed(); } @@ -714,12 +732,14 @@ EditorVisualProfiler::EditorVisualProfiler() { add_child(hb); activate = memnew(Button); activate->set_toggle_mode(true); + activate->set_disabled(true); activate->set_text(TTR("Start")); activate->connect("pressed", callable_mp(this, &EditorVisualProfiler::_activate_pressed)); hb->add_child(activate); clear_button = memnew(Button); clear_button->set_text(TTR("Clear")); + clear_button->set_disabled(true); clear_button->connect("pressed", callable_mp(this, &EditorVisualProfiler::_clear_pressed)); hb->add_child(clear_button); diff --git a/editor/debugger/editor_visual_profiler.h b/editor/debugger/editor_visual_profiler.h index 8aa9e7b308..8180d354e8 100644 --- a/editor/debugger/editor_visual_profiler.h +++ b/editor/debugger/editor_visual_profiler.h @@ -101,6 +101,8 @@ private: Timer *frame_delay = nullptr; Timer *plot_delay = nullptr; + void _update_button_text(); + void _update_frame(bool p_focus_selected = false); void _activate_pressed(); @@ -133,6 +135,7 @@ protected: public: void add_frame_metric(const Metric &p_metric); void set_enabled(bool p_enable); + void set_pressed(bool p_pressed); bool is_profiling(); bool is_seeking() { return seeking; } void disable_seeking(); diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 5cb7016b35..f6b00b83b0 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -319,6 +319,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da tabs->set_current_tab(0); } profiler->set_enabled(false, false); + visual_profiler->set_enabled(false); inspector->clear_cache(); // Take a chance to force remote objects update. } else if (p_msg == "debug_exit") { @@ -328,8 +329,12 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da _update_buttons_state(); _set_reason_text(TTR("Execution resumed."), MESSAGE_SUCCESS); emit_signal(SNAME("breaked"), false, false, "", false); + profiler->set_enabled(true, false); profiler->disable_seeking(); + + visual_profiler->set_enabled(true); + } else if (p_msg == "set_pid") { ERR_FAIL_COND(p_data.size() < 1); remote_pid = p_data[0]; @@ -901,6 +906,7 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) { stop(); profiler->set_enabled(true, true); + visual_profiler->set_enabled(true); peer = p_peer; ERR_FAIL_COND(p_peer.is_null()); @@ -957,7 +963,11 @@ void ScriptEditorDebugger::stop() { res_path_cache.clear(); profiler_signature.clear(); - profiler->set_enabled(true, false); + profiler->set_enabled(false, false); + profiler->set_pressed(false); + + visual_profiler->set_enabled(false); + visual_profiler->set_pressed(false); inspector->edit(nullptr); _update_buttons_state(); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index f15b874c45..e593d652ad 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -947,9 +947,10 @@ Variant EditorData::script_class_instance(const String &p_class) { if (ScriptServer::is_global_class(p_class)) { Ref<Script> script = script_class_load_script(p_class); if (script.is_valid()) { - Object *obj = ClassDB::instantiate(script->get_instance_base_type()); + // Store in a variant to initialize the refcount if needed. + Variant obj = ClassDB::instantiate(script->get_instance_base_type()); if (obj) { - obj->set_script(script); + obj.operator Object *()->set_script(script); } return obj; } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 2df14aef6c..88a1bbb4a9 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1172,6 +1172,36 @@ void EditorInspectorSection::_test_unfold() { } } +Ref<Texture2D> EditorInspectorSection::_get_arrow() { + Ref<Texture2D> arrow; + if (foldable) { + if (object->editor_is_section_unfolded(section)) { + arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree")); + } else { + if (is_layout_rtl()) { + arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree")); + } else { + arrow = get_theme_icon(SNAME("arrow_collapsed"), SNAME("Tree")); + } + } + } + return arrow; +} + +int EditorInspectorSection::_get_header_height() { + Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts")); + int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); + + int header_height = font->get_height(font_size); + Ref<Texture2D> arrow = _get_arrow(); + if (arrow.is_valid()) { + header_height = MAX(header_height, arrow->get_height()); + } + header_height += get_theme_constant(SNAME("v_separation"), SNAME("Tree")); + + return header_height; +} + void EditorInspectorSection::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { @@ -1182,30 +1212,6 @@ void EditorInspectorSection::_notification(int p_what) { if (!vbox_added) { return; } - // Get the section header font. - Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts")); - int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); - - // Get the right direction arrow texture, if the section is foldable. - Ref<Texture2D> arrow; - if (foldable) { - if (object->editor_is_section_unfolded(section)) { - arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree")); - } else { - if (is_layout_rtl()) { - arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree")); - } else { - arrow = get_theme_icon(SNAME("arrow_collapsed"), SNAME("Tree")); - } - } - } - - // Compute the height of the section header. - int header_height = font->get_height(font_size); - if (arrow.is_valid()) { - header_height = MAX(header_height, arrow->get_height()); - } - header_height += get_theme_constant(SNAME("v_separation"), SNAME("Tree")); int inspector_margin = get_theme_constant(SNAME("inspector_margin"), SNAME("Editor")); int section_indent_size = get_theme_constant(SNAME("indent_size"), SNAME("EditorInspectorSection")); @@ -1218,6 +1224,7 @@ void EditorInspectorSection::_notification(int p_what) { } Size2 size = get_size() - Vector2(inspector_margin, 0); + int header_height = _get_header_height(); Vector2 offset = Vector2(is_layout_rtl() ? 0 : inspector_margin, header_height); for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); @@ -1233,36 +1240,6 @@ void EditorInspectorSection::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - // Get the section header font. - Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts")); - int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); - Color font_color = get_theme_color(SNAME("font_color"), SNAME("Editor")); - - // Get the right direction arrow texture, if the section is foldable. - Ref<Texture2D> arrow; - bool folded = foldable; - if (foldable) { - if (object->editor_is_section_unfolded(section)) { - arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree")); - folded = false; - } else { - if (is_layout_rtl()) { - arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree")); - } else { - arrow = get_theme_icon(SNAME("arrow_collapsed"), SNAME("Tree")); - } - } - } - - bool rtl = is_layout_rtl(); - - // Compute the height and width of the section header. - int header_height = font->get_height(font_size); - if (arrow.is_valid()) { - header_height = MAX(header_height, arrow->get_height()); - } - header_height += get_theme_constant(SNAME("v_separation"), SNAME("Tree")); - int section_indent = 0; int section_indent_size = get_theme_constant(SNAME("indent_size"), SNAME("EditorInspectorSection")); if (indent_depth > 0 && section_indent_size > 0) { @@ -1275,11 +1252,13 @@ void EditorInspectorSection::_notification(int p_what) { int header_width = get_size().width - section_indent; int header_offset_x = 0.0; + bool rtl = is_layout_rtl(); if (!rtl) { header_offset_x += section_indent; } // Draw header area. + int header_height = _get_header_height(); Rect2 header_rect = Rect2(Vector2(header_offset_x, 0.0), Vector2(header_width, header_height)); Color c = bg_color; c.a *= 0.4; @@ -1288,7 +1267,7 @@ void EditorInspectorSection::_notification(int p_what) { } draw_rect(header_rect, c); - // Draw header title, folding arrow and coutn of revertable properties. + // Draw header title, folding arrow and count of revertable properties. { int separation = Math::round(2 * EDSCALE); @@ -1296,6 +1275,7 @@ void EditorInspectorSection::_notification(int p_what) { int margin_end = separation; // - Arrow. + Ref<Texture2D> arrow = _get_arrow(); if (arrow.is_valid()) { Point2 arrow_position; if (rtl) { @@ -1313,6 +1293,13 @@ void EditorInspectorSection::_notification(int p_what) { // - Count of revertable properties. String num_revertable_str; int num_revertable_width = 0; + + bool folded = foldable && !object->editor_is_section_unfolded(section); + + Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts")); + int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")); + Color font_color = get_theme_color(SNAME("font_color"), SNAME("Editor")); + if (folded && revertable_properties.size()) { int label_width = font->get_string_size(label, HORIZONTAL_ALIGNMENT_LEFT, available, font_size, TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS).x; @@ -1481,10 +1468,12 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { - Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Tree")); - int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Tree")); - if (mb->get_position().y > font->get_height(font_size)) { //clicked outside - return; + if (object->editor_is_section_unfolded(section)) { + int header_height = _get_header_height(); + + if (mb->get_position().y >= header_height) { + return; + } } accept_event(); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 56d0a55319..53490f0880 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -280,6 +280,8 @@ class EditorInspectorSection : public Container { HashSet<StringName> revertable_properties; void _test_unfold(); + int _get_header_height(); + Ref<Texture2D> _get_arrow(); protected: Object *object = nullptr; diff --git a/editor/editor_layouts_dialog.cpp b/editor/editor_layouts_dialog.cpp index 886e29a504..19b137c7fd 100644 --- a/editor/editor_layouts_dialog.cpp +++ b/editor/editor_layouts_dialog.cpp @@ -33,6 +33,7 @@ #include "core/io/config_file.h" #include "core/object/class_db.h" #include "core/os/keyboard.h" +#include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "scene/gui/item_list.h" #include "scene/gui/line_edit.h" @@ -97,6 +98,11 @@ void EditorLayoutsDialog::_post_popup() { for (const String &E : layouts) { layout_names->add_item(E); } + if (name->is_visible()) { + name->grab_focus(); + } else { + layout_names->grab_focus(); + } } EditorLayoutsDialog::EditorLayoutsDialog() { @@ -106,7 +112,9 @@ EditorLayoutsDialog::EditorLayoutsDialog() { makevb->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5); layout_names = memnew(ItemList); - makevb->add_child(layout_names); + layout_names->set_auto_height(true); + makevb->add_margin_child(TTR("Select existing layout:"), layout_names); + layout_names->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); layout_names->set_visible(true); layout_names->set_offset(SIDE_TOP, 5); layout_names->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5); @@ -116,8 +124,10 @@ EditorLayoutsDialog::EditorLayoutsDialog() { layout_names->set_allow_rmb_select(true); name = memnew(LineEdit); + name->set_placeholder("Or enter new layout name"); makevb->add_child(name); name->set_offset(SIDE_TOP, 5); + name->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); name->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5); name->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5); name->connect("gui_input", callable_mp(this, &EditorLayoutsDialog::_line_gui_input)); diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 84284a7f31..a232c83783 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -286,7 +286,7 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) { // Remove last line if replacing, as it will be replace by the next added line. // Why "- 2"? RichTextLabel is weird. When you add a line with add_newline(), it also adds an element to the list of lines which is null/blank, // but it still counts as a line. So if you remove the last line (count - 1) you are actually removing nothing... - log->remove_line(log->get_paragraph_count() - 2); + log->remove_paragraph(log->get_paragraph_count() - 2); } switch (p_message.type) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 02cfd3e873..01e605880c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -96,6 +96,7 @@ #include "editor/export/editor_export.h" #include "editor/export/export_template_manager.h" #include "editor/export/project_export.h" +#include "editor/fbx_importer_manager.h" #include "editor/filesystem_dock.h" #include "editor/history_dock.h" #include "editor/import/audio_stream_import_settings.h" @@ -2981,7 +2982,11 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case SETTINGS_MANAGE_EXPORT_TEMPLATES: { export_template_manager->popup_manager(); - + } break; + case SETTINGS_MANAGE_FBX_IMPORTER: { +#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED) + fbx_importer_manager->show_dialog(); +#endif } break; case SETTINGS_INSTALL_ANDROID_BUILD_TEMPLATE: { custom_build_manage_templates->hide(); @@ -5189,15 +5194,15 @@ void EditorNode::_layout_menu_option(int p_id) { current_menu_option = p_id; layout_dialog->set_title(TTR("Save Layout")); layout_dialog->set_ok_button_text(TTR("Save")); - layout_dialog->popup_centered(); layout_dialog->set_name_line_enabled(true); + layout_dialog->popup_centered(); } break; case SETTINGS_LAYOUT_DELETE: { current_menu_option = p_id; layout_dialog->set_title(TTR("Delete Layout")); layout_dialog->set_ok_button_text(TTR("Delete")); - layout_dialog->popup_centered(); layout_dialog->set_name_line_enabled(false); + layout_dialog->popup_centered(); } break; case SETTINGS_LAYOUT_DEFAULT: { _load_docks_from_config(default_layout, "docks"); @@ -6624,6 +6629,11 @@ EditorNode::EditorNode() { gui_base->add_child(about); feature_profile_manager->connect("current_feature_profile_changed", callable_mp(this, &EditorNode::_feature_profile_changed)); +#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED) + fbx_importer_manager = memnew(FBXImporterManager); + gui_base->add_child(fbx_importer_manager); +#endif + warning = memnew(AcceptDialog); warning->add_button(TTR("Copy Text"), true, "copy"); gui_base->add_child(warning); @@ -6796,6 +6806,9 @@ EditorNode::EditorNode() { #ifndef ANDROID_ENABLED settings_menu->add_item(TTR("Manage Export Templates..."), SETTINGS_MANAGE_EXPORT_TEMPLATES); #endif +#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED) + settings_menu->add_item(TTR("Configure FBX Importer..."), SETTINGS_MANAGE_FBX_IMPORTER); +#endif help_menu = memnew(PopupMenu); help_menu->set_name(TTR("Help")); @@ -7249,6 +7262,7 @@ EditorNode::EditorNode() { gui_base->add_child(disk_changed); add_editor_plugin(memnew(AnimationPlayerEditorPlugin)); + add_editor_plugin(memnew(AnimationTrackKeyEditEditorPlugin)); add_editor_plugin(memnew(CanvasItemEditorPlugin)); add_editor_plugin(memnew(Node3DEditorPlugin)); add_editor_plugin(memnew(ScriptEditorPlugin)); diff --git a/editor/editor_node.h b/editor/editor_node.h index c430662c7f..950970379d 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -77,6 +77,7 @@ class EditorSettingsDialog; class EditorToaster; class EditorUndoRedoManager; class ExportTemplateManager; +class FBXImporterManager; class FileDialog; class FileSystemDock; class HistoryDock; @@ -209,6 +210,7 @@ private: SETTINGS_EDITOR_DATA_FOLDER, SETTINGS_EDITOR_CONFIG_FOLDER, SETTINGS_MANAGE_EXPORT_TEMPLATES, + SETTINGS_MANAGE_FBX_IMPORTER, SETTINGS_MANAGE_FEATURE_PROFILES, SETTINGS_INSTALL_ANDROID_BUILD_TEMPLATE, SETTINGS_PICK_MAIN_SCENE, @@ -285,6 +287,8 @@ private: ProjectExportDialog *project_export = nullptr; ProjectSettingsEditor *project_settings_editor = nullptr; + FBXImporterManager *fbx_importer_manager = nullptr; + Vector<EditorPlugin *> editor_plugins; bool _initializing_plugins = false; HashMap<String, EditorPlugin *> addon_name_to_plugin; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index fb3bf46c05..4c9b18efe7 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1384,10 +1384,11 @@ void EditorPropertyInteger::update_property() { void EditorPropertyInteger::_bind_methods() { } -void EditorPropertyInteger::setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix) { +void EditorPropertyInteger::setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_hide_slider, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix) { spin->set_min(p_min); spin->set_max(p_max); spin->set_step(p_step); + spin->set_hide_slider(p_hide_slider); spin->set_allow_greater(p_allow_greater); spin->set_allow_lesser(p_allow_lesser); spin->set_suffix(p_suffix); @@ -2242,12 +2243,11 @@ void EditorPropertyVector2i::_notification(int p_what) { } } -void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_hide_slider, bool p_link, const String &p_suffix) { +void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_link, const String &p_suffix) { for (int i = 0; i < 2; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); spin[i]->set_step(1); - spin[i]->set_hide_slider(p_hide_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); spin[i]->set_suffix(p_suffix); @@ -2352,12 +2352,11 @@ void EditorPropertyRect2i::_notification(int p_what) { void EditorPropertyRect2i::_bind_methods() { } -void EditorPropertyRect2i::setup(int p_min, int p_max, bool p_hide_slider, const String &p_suffix) { +void EditorPropertyRect2i::setup(int p_min, int p_max, const String &p_suffix) { for (int i = 0; i < 4; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); spin[i]->set_step(1); - spin[i]->set_hide_slider(p_hide_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); spin[i]->set_suffix(p_suffix); @@ -2496,12 +2495,12 @@ void EditorPropertyVector3i::_notification(int p_what) { void EditorPropertyVector3i::_bind_methods() { } -void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_hide_slider, bool p_link, const String &p_suffix) { +void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_link, const String &p_suffix) { for (int i = 0; i < 3; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); spin[i]->set_step(1); - spin[i]->set_hide_slider(p_hide_slider); + spin[i]->set_hide_slider(false); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); spin[i]->set_suffix(p_suffix); @@ -3004,11 +3003,11 @@ void EditorPropertyVector4i::_notification(int p_what) { void EditorPropertyVector4i::_bind_methods() { } -void EditorPropertyVector4i::setup(double p_min, double p_max, bool p_hide_slider, const String &p_suffix) { +void EditorPropertyVector4i::setup(double p_min, double p_max, const String &p_suffix) { for (int i = 0; i < 4; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); - spin[i]->set_hide_slider(p_hide_slider); + spin[i]->set_step(1); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); spin[i]->set_suffix(p_suffix); @@ -4347,7 +4346,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ EditorPropertyInteger *editor = memnew(EditorPropertyInteger); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); - editor->setup(hint.min, hint.max, hint.step, hint.or_greater, hint.or_less, hint.suffix); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.or_greater, hint.or_less, hint.suffix); return editor; } @@ -4475,7 +4474,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ case Variant::VECTOR2I: { EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i(p_wide)); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); - editor->setup(hint.min, hint.max, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix); + editor->setup(hint.min, hint.max, p_hint == PROPERTY_HINT_LINK, hint.suffix); return editor; } break; @@ -4488,7 +4487,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ case Variant::RECT2I: { EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i(p_wide)); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); - editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix); + editor->setup(hint.min, hint.max, hint.suffix); return editor; } break; @@ -4502,7 +4501,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ case Variant::VECTOR3I: { EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i(p_wide)); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); - editor->setup(hint.min, hint.max, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix); + editor->setup(hint.min, hint.max, p_hint == PROPERTY_HINT_LINK, hint.suffix); return editor; } break; @@ -4516,7 +4515,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ case Variant::VECTOR4I: { EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); - editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix); + editor->setup(hint.min, hint.max, hint.suffix); return editor; } break; diff --git a/editor/editor_properties.h b/editor/editor_properties.h index f38e33d9e3..042b94130b 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -378,7 +378,7 @@ protected: public: virtual void update_property() override; - void setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix = String()); + void setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_hide_slider, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix = String()); EditorPropertyInteger(); }; @@ -566,7 +566,7 @@ protected: public: virtual void update_property() override; - void setup(int p_min, int p_max, bool p_hide_slider, bool p_link = false, const String &p_suffix = String()); + void setup(int p_min, int p_max, bool p_link = false, const String &p_suffix = String()); EditorPropertyVector2i(bool p_force_wide = false); }; @@ -583,7 +583,7 @@ protected: public: virtual void update_property() override; - void setup(int p_min, int p_max, bool p_hide_slider, const String &p_suffix = String()); + void setup(int p_min, int p_max, const String &p_suffix = String()); EditorPropertyRect2i(bool p_force_wide = false); }; @@ -608,7 +608,7 @@ protected: public: virtual void update_property() override; - void setup(int p_min, int p_max, bool p_hide_slider, bool p_link = false, const String &p_suffix = String()); + void setup(int p_min, int p_max, bool p_link = false, const String &p_suffix = String()); EditorPropertyVector3i(bool p_force_wide = false); }; @@ -693,7 +693,7 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, bool p_hide_slider, const String &p_suffix = String()); + void setup(double p_min, double p_max, const String &p_suffix = String()); EditorPropertyVector4i(); }; diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index edda6c5d7b..451cb7cfee 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -919,7 +919,7 @@ void EditorPropertyDictionary::update_property() { } break; case Variant::INT: { EditorPropertyInteger *editor = memnew(EditorPropertyInteger); - editor->setup(-100000, 100000, 1, true, true); + editor->setup(-100000, 100000, 1, false, true, true); prop = editor; } break; @@ -942,7 +942,7 @@ void EditorPropertyDictionary::update_property() { } break; case Variant::VECTOR2I: { EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i); - editor->setup(-100000, 100000, true); + editor->setup(-100000, 100000); prop = editor; } break; @@ -954,7 +954,7 @@ void EditorPropertyDictionary::update_property() { } break; case Variant::RECT2I: { EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i); - editor->setup(-100000, 100000, true); + editor->setup(-100000, 100000); prop = editor; } break; @@ -966,7 +966,7 @@ void EditorPropertyDictionary::update_property() { } break; case Variant::VECTOR3I: { EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i); - editor->setup(-100000, 100000, true); + editor->setup(-100000, 100000); prop = editor; } break; @@ -978,7 +978,7 @@ void EditorPropertyDictionary::update_property() { } break; case Variant::VECTOR4I: { EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i); - editor->setup(-100000, 100000, true); + editor->setup(-100000, 100000); prop = editor; } break; diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index 9587e65cad..e8a0912d66 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -231,6 +231,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["tcp"] = "TCP"; capitalize_string_remaps["tls"] = "TLS"; capitalize_string_remaps["ui"] = "UI"; + capitalize_string_remaps["uri"] = "URI"; capitalize_string_remaps["url"] = "URL"; capitalize_string_remaps["urls"] = "URLs"; capitalize_string_remaps["us"] = String::utf8("(µs)"); // Unit. diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 9128143619..60c46835fe 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -76,6 +76,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) { pre_grab_value = get_value(); grabbing_spinner = false; grabbing_spinner_mouse_pos = get_global_mouse_position(); + emit_signal("grabbed"); } } else { if (grabbing_spinner_attempt) { @@ -83,6 +84,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) { Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); Input::get_singleton()->warp_mouse(grabbing_spinner_mouse_pos); queue_redraw(); + emit_signal("ungrabbed"); } else { _focus_entered(); } @@ -178,9 +180,11 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) { grabbing_ratio = get_as_ratio(); grabbing_from = grabber->get_transform().xform(mb->get_position()).x; } + emit_signal("grabbed"); } else { grabbing_grabber = false; mousewheel_over_grabber = false; + emit_signal("ungrabbed"); } } @@ -299,10 +303,6 @@ void EditorSpinSlider::_draw_spin_slider() { Ref<Texture2D> updown = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox")); - if (get_step() == 1) { - number_width -= updown->get_width(); - } - String numstr = get_text_value(); int vofs = (size.height - font->get_height(font_size)) / 2 + font->get_ascent(font_size); @@ -359,76 +359,79 @@ void EditorSpinSlider::_draw_spin_slider() { } TS->free_rid(num_rid); - if (get_step() == 1) { - Ref<Texture2D> updown2 = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox")); - int updown_vofs = (size.height - updown2->get_height()) / 2; - if (rtl) { - updown_offset = sb->get_margin(SIDE_LEFT); - } else { - updown_offset = size.width - sb->get_margin(SIDE_RIGHT) - updown2->get_width(); - } - Color c(1, 1, 1); - if (hover_updown) { - c *= Color(1.2, 1.2, 1.2); - } - draw_texture(updown2, Vector2(updown_offset, updown_vofs), c); - if (grabber->is_visible()) { - grabber->hide(); - } - } else if (!hide_slider) { - const int grabber_w = 4 * EDSCALE; - const int width = size.width - sb->get_minimum_size().width - grabber_w; - const int ofs = sb->get_offset().x; - const int svofs = (size.height + vofs) / 2 - 1; - Color c = fc; - - // Draw the horizontal slider's background. - c.a = 0.2; - draw_rect(Rect2(ofs, svofs + 1, width, 2 * EDSCALE), c); - - // Draw the horizontal slider's filled part on the left. - const int gofs = get_as_ratio() * width; - c.a = 0.45; - draw_rect(Rect2(ofs, svofs + 1, gofs, 2 * EDSCALE), c); - - // Draw the horizontal slider's grabber. - c.a = 0.9; - const Rect2 grabber_rect = Rect2(ofs + gofs, svofs, grabber_w, 4 * EDSCALE); - draw_rect(grabber_rect, c); - - grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.get_center(); - - bool display_grabber = (grabbing_grabber || mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !(value_input_popup && value_input_popup->is_visible()); - if (grabber->is_visible() != display_grabber) { - if (display_grabber) { - grabber->show(); + if (!hide_slider) { + if (get_step() == 1) { + number_width -= updown->get_width(); + Ref<Texture2D> updown2 = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox")); + int updown_vofs = (size.height - updown2->get_height()) / 2; + if (rtl) { + updown_offset = sb->get_margin(SIDE_LEFT); } else { + updown_offset = size.width - sb->get_margin(SIDE_RIGHT) - updown2->get_width(); + } + Color c(1, 1, 1); + if (hover_updown) { + c *= Color(1.2, 1.2, 1.2); + } + draw_texture(updown2, Vector2(updown_offset, updown_vofs), c); + if (grabber->is_visible()) { grabber->hide(); } - } - - if (display_grabber) { - Ref<Texture2D> grabber_tex; - if (mouse_over_grabber) { - grabber_tex = get_theme_icon(SNAME("grabber_highlight"), SNAME("HSlider")); - } else { - grabber_tex = get_theme_icon(SNAME("grabber"), SNAME("HSlider")); + } else { + const int grabber_w = 4 * EDSCALE; + const int width = size.width - sb->get_minimum_size().width - grabber_w; + const int ofs = sb->get_offset().x; + const int svofs = (size.height + vofs) / 2 - 1; + Color c = fc; + + // Draw the horizontal slider's background. + c.a = 0.2; + draw_rect(Rect2(ofs, svofs + 1, width, 2 * EDSCALE), c); + + // Draw the horizontal slider's filled part on the left. + const int gofs = get_as_ratio() * width; + c.a = 0.45; + draw_rect(Rect2(ofs, svofs + 1, gofs, 2 * EDSCALE), c); + + // Draw the horizontal slider's grabber. + c.a = 0.9; + const Rect2 grabber_rect = Rect2(ofs + gofs, svofs, grabber_w, 4 * EDSCALE); + draw_rect(grabber_rect, c); + + grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.get_center(); + + bool display_grabber = (grabbing_grabber || mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !(value_input_popup && value_input_popup->is_visible()); + if (grabber->is_visible() != display_grabber) { + if (display_grabber) { + grabber->show(); + } else { + grabber->hide(); + } } - if (grabber->get_texture() != grabber_tex) { - grabber->set_texture(grabber_tex); - } + if (display_grabber) { + Ref<Texture2D> grabber_tex; + if (mouse_over_grabber) { + grabber_tex = get_theme_icon(SNAME("grabber_highlight"), SNAME("HSlider")); + } else { + grabber_tex = get_theme_icon(SNAME("grabber"), SNAME("HSlider")); + } - Vector2 scale = get_global_transform_with_canvas().get_scale(); - grabber->set_scale(scale); - grabber->reset_size(); - grabber->set_position(get_global_position() + (grabber_rect.get_center() - grabber->get_size() * 0.5) * scale); + if (grabber->get_texture() != grabber_tex) { + grabber->set_texture(grabber_tex); + } - if (mousewheel_over_grabber) { - Input::get_singleton()->warp_mouse(grabber->get_position() + grabber_rect.size); - } + Vector2 scale = get_global_transform_with_canvas().get_scale(); + grabber->set_scale(scale); + grabber->reset_size(); + grabber->set_position(get_global_position() + (grabber_rect.get_center() - grabber->get_size() * 0.5) * scale); + + if (mousewheel_over_grabber) { + Input::get_singleton()->warp_mouse(grabber->get_position() + grabber_rect.size); + } - grabber_range = width; + grabber_range = width; + } } } } @@ -584,6 +587,8 @@ void EditorSpinSlider::_value_focus_exited() { //enter, click, esc grab_focus(); } + + emit_signal("value_focus_exited"); } void EditorSpinSlider::_grabber_mouse_entered() { @@ -627,6 +632,7 @@ void EditorSpinSlider::_focus_entered() { value_input->call_deferred(SNAME("select_all")); value_input->set_focus_next(find_next_valid_focus()->get_path()); value_input->set_focus_previous(find_prev_valid_focus()->get_path()); + emit_signal("value_focus_entered"); } void EditorSpinSlider::_bind_methods() { @@ -650,6 +656,11 @@ void EditorSpinSlider::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_slider"), "set_hide_slider", "is_hiding_slider"); + + ADD_SIGNAL(MethodInfo("grabbed")); + ADD_SIGNAL(MethodInfo("ungrabbed")); + ADD_SIGNAL(MethodInfo("value_focus_entered")); + ADD_SIGNAL(MethodInfo("value_focus_exited")); } void EditorSpinSlider::_ensure_input_popup() { diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp index d22c7bd149..3a6516fbfa 100644 --- a/editor/editor_vcs_interface.cpp +++ b/editor/editor_vcs_interface.cpp @@ -57,7 +57,7 @@ void EditorVCSInterface::set_credentials(String p_username, String p_password, S } List<String> EditorVCSInterface::get_remotes() { - TypedArray<Dictionary> result; + TypedArray<String> result; if (!GDVIRTUAL_CALL(_get_remotes, result)) { UNIMPLEMENTED(); return {}; @@ -137,7 +137,7 @@ List<EditorVCSInterface::Commit> EditorVCSInterface::get_previous_commits(int p_ } List<String> EditorVCSInterface::get_branch_list() { - TypedArray<Dictionary> result; + TypedArray<String> result; if (!GDVIRTUAL_CALL(_get_branch_list, result)) { UNIMPLEMENTED(); return {}; diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h index 5d4901cefa..c93fe4a672 100644 --- a/editor/editor_vcs_interface.h +++ b/editor/editor_vcs_interface.h @@ -117,8 +117,8 @@ protected: GDVIRTUAL0R(bool, _shut_down); GDVIRTUAL0R(String, _get_vcs_name); GDVIRTUAL1R(TypedArray<Dictionary>, _get_previous_commits, int); - GDVIRTUAL0R(TypedArray<Dictionary>, _get_branch_list); - GDVIRTUAL0R(TypedArray<Dictionary>, _get_remotes); + GDVIRTUAL0R(TypedArray<String>, _get_branch_list); + GDVIRTUAL0R(TypedArray<String>, _get_remotes); GDVIRTUAL1(_create_branch, String); GDVIRTUAL1(_remove_branch, String); GDVIRTUAL2(_create_remote, String, String); diff --git a/editor/fbx_importer_manager.cpp b/editor/fbx_importer_manager.cpp new file mode 100644 index 0000000000..b258fe7e09 --- /dev/null +++ b/editor/fbx_importer_manager.cpp @@ -0,0 +1,158 @@ +/*************************************************************************/ +/* fbx_importer_manager.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "fbx_importer_manager.h" + +#include "editor/editor_scale.h" +#include "editor/editor_settings.h" +#include "scene/gui/link_button.h" + +void FBXImporterManager::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + connect("confirmed", callable_mp(this, &FBXImporterManager::_path_confirmed)); + } break; + } +} + +void FBXImporterManager::show_dialog(bool p_exclusive) { + String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path"); + fbx_path->set_text(fbx2gltf_path); + _validate_path(fbx2gltf_path); + + set_flag(Window::FLAG_BORDERLESS, p_exclusive); // Avoid closing accidentally . + set_close_on_escape(!p_exclusive); + + popup_centered(); +} + +void FBXImporterManager::_validate_path(const String &p_path) { + String error; + bool success = false; + + if (p_path == "") { + error = TTR("Path to FBX2glTF executable is empty."); + } else if (!FileAccess::exists(p_path)) { + error = TTR("Path to FBX2glTF executable is invalid."); + } else { + List<String> args; + args.push_back("--version"); + int exitcode; + Error err = OS::get_singleton()->execute(p_path, args, nullptr, &exitcode); + + if (err == OK && exitcode == 0) { + success = true; + } else { + error = TTR("Error executing this file (wrong version or architecture)."); + } + } + + if (success) { + path_status->set_text(TTR("FBX2glTF executable is valid.")); + path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("success_color"), SNAME("Editor"))); + get_ok_button()->set_disabled(false); + } else { + path_status->set_text(error); + path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("error_color"), SNAME("Editor"))); + get_ok_button()->set_disabled(true); + } +} + +void FBXImporterManager::_select_file(const String &p_path) { + fbx_path->set_text(p_path); + _validate_path(p_path); +} + +void FBXImporterManager::_path_confirmed() { + String path = fbx_path->get_text(); + EditorSettings::get_singleton()->set("filesystem/import/fbx/fbx2gltf_path", path); + EditorSettings::get_singleton()->save(); +} + +void FBXImporterManager::_browse_install() { + if (fbx_path->get_text() != String()) { + browse_dialog->set_current_file(fbx_path->get_text()); + } + + browse_dialog->popup_centered_ratio(); +} + +FBXImporterManager *FBXImporterManager::singleton = nullptr; + +FBXImporterManager::FBXImporterManager() { + singleton = this; + + set_title(TTR("Configure FBX Importer")); + + VBoxContainer *vb = memnew(VBoxContainer); + vb->add_child(memnew(Label(TTR("FBX2glTF is required for importing FBX files.\nPlease download it and provide a valid path to the binary:")))); + LinkButton *lb = memnew(LinkButton); + lb->set_text(TTR("Click this link to download FBX2glTF")); + lb->set_uri("https://godotengine.org/fbx-import"); + vb->add_child(lb); + + HBoxContainer *hb = memnew(HBoxContainer); + + fbx_path = memnew(LineEdit); + fbx_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hb->add_child(fbx_path); + fbx_path_browse = memnew(Button); + hb->add_child(fbx_path_browse); + fbx_path_browse->set_text(TTR("Browse")); + fbx_path_browse->connect("pressed", callable_mp(this, &FBXImporterManager::_browse_install)); + hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hb->set_custom_minimum_size(Size2(400 * EDSCALE, 0)); + + vb->add_child(hb); + + path_status = memnew(Label); + vb->add_child(path_status); + + add_child(vb); + + fbx_path->connect("text_changed", callable_mp(this, &FBXImporterManager::_validate_path)); + + get_ok_button()->set_text(TTR("Confirm Path")); + + browse_dialog = memnew(EditorFileDialog); + browse_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); +#if defined(X11_ENABLED) + browse_dialog->add_filter("FBX2glTF-linux-x86_64"); +#elif defined(OSX_ENABLED) + browse_dialog->add_filter("FBX2glTF-macos-x86_64"); +#elif defined(WINDOWS_ENABLED) + browse_dialog->add_filter("FBX2glTF-windows-x86_64"); +#endif + + browse_dialog->connect("file_selected", callable_mp(this, &FBXImporterManager::_select_file)); + + add_child(browse_dialog); +} diff --git a/editor/fbx_importer_manager.h b/editor/fbx_importer_manager.h new file mode 100644 index 0000000000..28de761519 --- /dev/null +++ b/editor/fbx_importer_manager.h @@ -0,0 +1,66 @@ +/*************************************************************************/ +/* fbx_importer_manager.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef FBX_IMPORTER_MANAGER_H +#define FBX_IMPORTER_MANAGER_H + +#include "editor/editor_file_dialog.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/line_edit.h" + +class FBXImporterManager : public ConfirmationDialog { + GDCLASS(FBXImporterManager, ConfirmationDialog) + + Label *message = nullptr; + LineEdit *fbx_path = nullptr; + Button *fbx_path_browse = nullptr; + EditorFileDialog *browse_dialog = nullptr; + Label *path_status = nullptr; + + void _validate_path(const String &p_path); + void _select_file(const String &p_path); + void _path_confirmed(); + void _browse_install(); + void _link_clicked(); + + static FBXImporterManager *singleton; + +protected: + void _notification(int p_what); + +public: + static FBXImporterManager *get_singleton() { return singleton; } + + void show_dialog(bool p_exclusive = false); + + FBXImporterManager(); +}; + +#endif // FBX_IMPORTER_MANAGER_H diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index b7e7200b11..3a6c891142 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -569,8 +569,6 @@ FindInFilesPanel::FindInFilesPanel() { hbc->add_child(find_label); _search_text_label = memnew(Label); - _search_text_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("source"), SNAME("EditorFonts"))); - _search_text_label->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts"))); hbc->add_child(_search_text_label); _progress_bar = memnew(ProgressBar); @@ -598,8 +596,6 @@ FindInFilesPanel::FindInFilesPanel() { } _results_display = memnew(Tree); - _results_display->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("source"), SNAME("EditorFonts"))); - _results_display->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts"))); _results_display->set_v_size_flags(SIZE_EXPAND_FILL); _results_display->connect("item_selected", callable_mp(this, &FindInFilesPanel::_on_result_selected)); _results_display->connect("item_edited", callable_mp(this, &FindInFilesPanel::_on_item_edited)); @@ -688,13 +684,20 @@ void FindInFilesPanel::stop_search() { void FindInFilesPanel::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_PROCESS: { - _progress_bar->set_as_ratio(_finder->get_progress()); - } break; - case NOTIFICATION_THEME_CHANGED: { _search_text_label->add_theme_font_override("font", get_theme_font(SNAME("source"), SNAME("EditorFonts"))); + _search_text_label->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts"))); _results_display->add_theme_font_override("font", get_theme_font(SNAME("source"), SNAME("EditorFonts"))); + _results_display->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("source_size"), SNAME("EditorFonts"))); + + // Rebuild search tree. + if (!_finder->get_search_text().is_empty()) { + start_search(); + } + } break; + + case NOTIFICATION_PROCESS: { + _progress_bar->set_as_ratio(_finder->get_progress()); } break; } } diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp index f635c74547..92d4397c68 100644 --- a/editor/import/audio_stream_import_settings.cpp +++ b/editor/import/audio_stream_import_settings.cpp @@ -465,12 +465,17 @@ void AudioStreamImportSettings::_settings_changed() { updating_settings = true; stream->call("set_loop", loop->is_pressed()); stream->call("set_loop_offset", loop_offset->get_value()); + if (loop->is_pressed()) { + loop_offset->set_editable(true); + } else { + loop_offset->set_editable(false); + } + if (bpm_enabled->is_pressed()) { stream->call("set_bpm", bpm_edit->get_value()); - beats_enabled->show(); - beats_edit->show(); - bar_beats_label->show(); - bar_beats_edit->show(); + beats_enabled->set_disabled(false); + beats_edit->set_editable(true); + bar_beats_edit->set_editable(true); double bpm = bpm_edit->get_value(); if (bpm > 0) { float beat_size = 60 / float(bpm); @@ -486,10 +491,9 @@ void AudioStreamImportSettings::_settings_changed() { } else { stream->call("set_bpm", 0); stream->call("set_bar_beats", 4); - beats_enabled->hide(); - beats_edit->hide(); - bar_beats_label->hide(); - bar_beats_edit->hide(); + beats_enabled->set_disabled(true); + beats_edit->set_editable(false); + bar_beats_edit->set_editable(false); } if (bpm_enabled->is_pressed() && beats_enabled->is_pressed()) { stream->call("set_beat_count", beats_edit->get_value()); @@ -552,17 +556,8 @@ AudioStreamImportSettings::AudioStreamImportSettings() { bpm_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); interactive_hb->add_child(bpm_edit); interactive_hb->add_spacer(); - bar_beats_label = memnew(Label(TTR("Beats/Bar:"))); - interactive_hb->add_child(bar_beats_label); - bar_beats_edit = memnew(SpinBox); - bar_beats_edit->set_tooltip_text(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams.")); - bar_beats_edit->set_min(2); - bar_beats_edit->set_max(32); - bar_beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); - interactive_hb->add_child(bar_beats_edit); - interactive_hb->add_spacer(); beats_enabled = memnew(CheckBox); - beats_enabled->set_text(TTR("Length (in beats):")); + beats_enabled->set_text(TTR("Beat Count:")); beats_enabled->connect("toggled", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); interactive_hb->add_child(beats_enabled); beats_edit = memnew(SpinBox); @@ -570,6 +565,15 @@ AudioStreamImportSettings::AudioStreamImportSettings() { beats_edit->set_max(99999); beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); interactive_hb->add_child(beats_edit); + bar_beats_label = memnew(Label(TTR("Bar Beats:"))); + interactive_hb->add_child(bar_beats_label); + bar_beats_edit = memnew(SpinBox); + bar_beats_edit->set_tooltip_text(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams.")); + bar_beats_edit->set_min(2); + bar_beats_edit->set_max(32); + bar_beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1)); + interactive_hb->add_child(bar_beats_edit); + interactive_hb->add_spacer(); main_vbox->add_margin_child(TTR("Music Playback:"), interactive_hb); color_rect = memnew(ColorRect); diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index 1e406e6d17..380a4e370c 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -958,15 +958,15 @@ void SceneImportSettings::_notification(int p_what) { void SceneImportSettings::_menu_callback(int p_id) { switch (p_id) { case ACTION_EXTRACT_MATERIALS: { - save_path->set_text(TTR("Select folder to extract material resources")); + save_path->set_title(TTR("Select folder to extract material resources")); external_extension_type->select(0); } break; case ACTION_CHOOSE_MESH_SAVE_PATHS: { - save_path->set_text(TTR("Select folder where mesh resources will save on import")); + save_path->set_title(TTR("Select folder where mesh resources will save on import")); external_extension_type->select(1); } break; case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: { - save_path->set_text(TTR("Select folder where animations will save on import")); + save_path->set_title(TTR("Select folder where animations will save on import")); external_extension_type->select(1); } break; } diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 5183a738ae..344a800241 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -87,13 +87,13 @@ void AnimationPlayerEditor::_notification(int p_what) { } frame->set_value(player->get_current_animation_position()); track_editor->set_anim_pos(player->get_current_animation_position()); - } else if (!player->is_valid()) { // Reset timeline when the player has been stopped externally frame->set_value(0); } else if (last_active) { // Need the last frame after it stopped. frame->set_value(player->get_current_animation_position()); + track_editor->set_anim_pos(player->get_current_animation_position()); } last_active = player->is_playing(); @@ -423,7 +423,7 @@ void AnimationPlayerEditor::_select_anim_by_name(const String &p_anim) { _animation_selected(idx); } -double AnimationPlayerEditor::_get_editor_step() const { +float AnimationPlayerEditor::_get_editor_step() const { // Returns the effective snapping value depending on snapping modifiers, or 0 if snapping is disabled. if (track_editor->is_snap_enabled()) { const String current = player->get_assigned_animation(); @@ -434,7 +434,7 @@ double AnimationPlayerEditor::_get_editor_step() const { return Input::get_singleton()->is_key_pressed(Key::SHIFT) ? anim->get_step() * 0.25 : anim->get_step(); } - return 0.0; + return 0.0f; } void AnimationPlayerEditor::_animation_name_edited() { @@ -1922,10 +1922,12 @@ void AnimationPlayerEditorPlugin::_notification(int p_what) { } void AnimationPlayerEditorPlugin::_property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance) { - if (!anim_editor->get_track_editor()->has_keying()) { + AnimationTrackEditor *te = anim_editor->get_track_editor(); + if (!te || !te->has_keying()) { return; } - anim_editor->get_track_editor()->insert_value_key(p_keyed, p_value, p_advance); + te->_clear_selection(); + te->insert_value_key(p_keyed, p_value, p_advance); } void AnimationPlayerEditorPlugin::_transform_key_request(Object *sp, const String &p_sub, const Transform3D &p_key) { @@ -1971,3 +1973,26 @@ AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin() { AnimationPlayerEditorPlugin::~AnimationPlayerEditorPlugin() { } + +// AnimationTrackKeyEditEditorPlugin + +bool EditorInspectorPluginAnimationTrackKeyEdit::can_handle(Object *p_object) { + return Object::cast_to<AnimationTrackKeyEdit>(p_object) != nullptr; +} + +void EditorInspectorPluginAnimationTrackKeyEdit::parse_begin(Object *p_object) { + AnimationTrackKeyEdit *atk = Object::cast_to<AnimationTrackKeyEdit>(p_object); + ERR_FAIL_COND(!atk); + + atk_editor = memnew(AnimationTrackKeyEditEditor(atk->animation, atk->track, atk->key_ofs, atk->use_fps)); + add_custom_control(atk_editor); +} + +AnimationTrackKeyEditEditorPlugin::AnimationTrackKeyEditEditorPlugin() { + atk_plugin = memnew(EditorInspectorPluginAnimationTrackKeyEdit); + EditorInspector::add_inspector_plugin(atk_plugin); +} + +bool AnimationTrackKeyEditEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("AnimationTrackKeyEdit"); +} diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 53d460fc9e..8539d450e6 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -162,7 +162,7 @@ class AnimationPlayerEditor : public VBoxContainer { } onion; void _select_anim_by_name(const String &p_anim); - double _get_editor_step() const; + float _get_editor_step() const; void _play_pressed(); void _play_from_pressed(); void _play_bw_pressed(); @@ -272,4 +272,30 @@ public: ~AnimationPlayerEditorPlugin(); }; +// AnimationTrackKeyEditEditorPlugin + +class EditorInspectorPluginAnimationTrackKeyEdit : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginAnimationTrackKeyEdit, EditorInspectorPlugin); + + AnimationTrackKeyEditEditor *atk_editor = nullptr; + +public: + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; +}; + +class AnimationTrackKeyEditEditorPlugin : public EditorPlugin { + GDCLASS(AnimationTrackKeyEditEditorPlugin, EditorPlugin); + + EditorInspectorPluginAnimationTrackKeyEdit *atk_plugin = nullptr; + +public: + bool has_main_screen() const override { return false; } + virtual bool handles(Object *p_object) const override; + + virtual String get_name() const override { return "AnimationTrackKeyEdit"; } + + AnimationTrackKeyEditEditorPlugin(); +}; + #endif // ANIMATION_PLAYER_EDITOR_PLUGIN_H diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 66a0c746d9..7b8a5d06f8 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1097,7 +1097,8 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action Ref<AnimationNodeStateMachineTransition> tr; tr.instantiate(); - tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected())); + tr->set_advance_mode(auto_advance->is_pressed() ? AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_AUTO : AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_ENABLED); + tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected())); Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); if (!p_nested_action) { @@ -1326,7 +1327,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } } - _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()), true, false, false, false, false); + _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, false, false); } Ref<Texture2D> tr_reference_icon = get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons")); @@ -1349,8 +1350,8 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { tl.to = (state_machine->get_node_position(local_to) * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE; Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i); - tl.disabled = tr->is_disabled(); - tl.auto_advance = tr->has_auto_advance(); + tl.disabled = bool(tr->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED); + tl.auto_advance = bool(tr->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_AUTO); tl.advance_condition_name = tr->get_advance_condition_name(); tl.advance_condition_state = false; tl.mode = tr->get_switch_mode(); @@ -1590,10 +1591,12 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { tool_create->set_icon(get_theme_icon(SNAME("ToolAddNode"), SNAME("EditorIcons"))); tool_connect->set_icon(get_theme_icon(SNAME("ToolConnect"), SNAME("EditorIcons"))); - transition_mode->clear(); - transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionImmediate"), SNAME("EditorIcons")), TTR("Immediate")); - transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionSync"), SNAME("EditorIcons")), TTR("Sync")); - transition_mode->add_icon_item(get_theme_icon(SNAME("TransitionEnd"), SNAME("EditorIcons")), TTR("At End")); + switch_mode->clear(); + switch_mode->add_icon_item(get_theme_icon(SNAME("TransitionImmediate"), SNAME("EditorIcons")), TTR("Immediate")); + switch_mode->add_icon_item(get_theme_icon(SNAME("TransitionSync"), SNAME("EditorIcons")), TTR("Sync")); + switch_mode->add_icon_item(get_theme_icon(SNAME("TransitionEnd"), SNAME("EditorIcons")), TTR("At End")); + + auto_advance->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons"))); tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); tool_group->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons"))); @@ -1652,12 +1655,12 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { break; } - if (transition_lines[i].disabled != state_machine->get_transition(tidx)->is_disabled()) { + if (transition_lines[i].disabled != bool(state_machine->get_transition(tidx)->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED)) { state_machine_draw->queue_redraw(); break; } - if (transition_lines[i].auto_advance != state_machine->get_transition(tidx)->has_auto_advance()) { + if (transition_lines[i].auto_advance != bool(state_machine->get_transition(tidx)->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_AUTO)) { state_machine_draw->queue_redraw(); break; } @@ -1904,7 +1907,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action void AnimationNodeStateMachineEditor::_update_mode() { if (tool_select->is_pressed()) { - tool_erase_hb->show(); + selection_tools_hb->show(); bool nothing_selected = selected_nodes.is_empty() && selected_transition_from == StringName() && selected_transition_to == StringName(); bool start_end_selected = selected_nodes.size() == 1 && (*selected_nodes.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node); tool_erase->set_disabled(nothing_selected || start_end_selected || read_only); @@ -1927,7 +1930,13 @@ void AnimationNodeStateMachineEditor::_update_mode() { } } } else { - tool_erase_hb->hide(); + selection_tools_hb->hide(); + } + + if (tool_connect->is_pressed()) { + transition_tools_hb->show(); + } else { + transition_tools_hb->hide(); } } @@ -1978,35 +1987,48 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { tool_connect->set_tooltip_text(TTR("Connect nodes.")); tool_connect->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED); - tool_erase_hb = memnew(HBoxContainer); - top_hb->add_child(tool_erase_hb); - tool_erase_hb->add_child(memnew(VSeparator)); + // Context-sensitive selection tools: + selection_tools_hb = memnew(HBoxContainer); + top_hb->add_child(selection_tools_hb); + selection_tools_hb->add_child(memnew(VSeparator)); tool_group = memnew(Button); tool_group->set_flat(true); tool_group->set_tooltip_text(TTR("Group Selected Node(s)") + " (Ctrl+G)"); tool_group->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_group_selected_nodes)); tool_group->set_disabled(true); - tool_erase_hb->add_child(tool_group); + selection_tools_hb->add_child(tool_group); tool_ungroup = memnew(Button); tool_ungroup->set_flat(true); tool_ungroup->set_tooltip_text(TTR("Ungroup Selected Node") + " (Ctrl+Shift+G)"); tool_ungroup->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_ungroup_selected_nodes)); tool_ungroup->set_visible(false); - tool_erase_hb->add_child(tool_ungroup); + selection_tools_hb->add_child(tool_ungroup); tool_erase = memnew(Button); tool_erase->set_flat(true); tool_erase->set_tooltip_text(TTR("Remove selected node or transition.")); tool_erase->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_erase_selected).bind(false)); tool_erase->set_disabled(true); - tool_erase_hb->add_child(tool_erase); + selection_tools_hb->add_child(tool_erase); + + transition_tools_hb = memnew(HBoxContainer); + top_hb->add_child(transition_tools_hb); + transition_tools_hb->add_child(memnew(VSeparator)); + + transition_tools_hb->add_child(memnew(Label(TTR("Transition:")))); + switch_mode = memnew(OptionButton); + transition_tools_hb->add_child(switch_mode); + + auto_advance = memnew(Button); + auto_advance->set_flat(true); + auto_advance->set_tooltip_text(TTR("New Transitions Should Auto Advance")); + auto_advance->set_toggle_mode(true); + auto_advance->set_pressed(true); + transition_tools_hb->add_child(auto_advance); - top_hb->add_child(memnew(VSeparator)); - top_hb->add_child(memnew(Label(TTR("Transition:")))); - transition_mode = memnew(OptionButton); - top_hb->add_child(transition_mode); + // top_hb->add_spacer(); diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 5edf803c41..28b5f0cbcc 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -52,15 +52,18 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { Button *tool_select = nullptr; Button *tool_create = nullptr; Button *tool_connect = nullptr; - Button *tool_group = nullptr; - Button *tool_ungroup = nullptr; Popup *name_edit_popup = nullptr; LineEdit *name_edit = nullptr; - HBoxContainer *tool_erase_hb = nullptr; + HBoxContainer *selection_tools_hb = nullptr; + Button *tool_group = nullptr; + Button *tool_ungroup = nullptr; Button *tool_erase = nullptr; - OptionButton *transition_mode = nullptr; + HBoxContainer *transition_tools_hb = nullptr; + OptionButton *switch_mode = nullptr; + Button *auto_advance = nullptr; + OptionButton *play_mode = nullptr; PanelContainer *panel = nullptr; diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 7c3ecd5d4e..6483a18a4d 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -43,6 +43,11 @@ #include "editor/project_settings_editor.h" #include "scene/gui/menu_button.h" +#include "modules/modules_enabled.gen.h" // For svg. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif + static inline void setup_http_request(HTTPRequest *request) { request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true)); @@ -751,13 +756,30 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB uint8_t png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; uint8_t jpg_signature[3] = { 255, 216, 255 }; + uint8_t webp_signature[4] = { 82, 73, 70, 70 }; + uint8_t bmp_signature[2] = { 66, 77 }; if (r) { if ((memcmp(&r[0], &png_signature[0], 8) == 0) && Image::_png_mem_loader_func) { image->copy_internals_from(Image::_png_mem_loader_func(r, len)); } else if ((memcmp(&r[0], &jpg_signature[0], 3) == 0) && Image::_jpg_mem_loader_func) { image->copy_internals_from(Image::_jpg_mem_loader_func(r, len)); + } else if ((memcmp(&r[0], &webp_signature[0], 4) == 0) && Image::_webp_mem_loader_func) { + image->copy_internals_from(Image::_webp_mem_loader_func(r, len)); + } else if ((memcmp(&r[0], &bmp_signature[0], 2) == 0) && Image::_bmp_mem_loader_func) { + image->copy_internals_from(Image::_bmp_mem_loader_func(r, len)); } +#ifdef MODULE_SVG_ENABLED + else { + ImageLoaderSVG svg_loader; + Ref<Image> img = Ref<Image>(memnew(Image)); + Error err = svg_loader.create_image_from_utf8_buffer(img, image_data, 1.0, false); + + if (err == OK) { + image->copy_internals_from(img); + } + } +#endif } if (!image->is_empty()) { diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp new file mode 100644 index 0000000000..60d949cdf0 --- /dev/null +++ b/editor/plugins/audio_stream_editor_plugin.cpp @@ -0,0 +1,280 @@ +/*************************************************************************/ +/* audio_stream_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "audio_stream_editor_plugin.h" + +#include "core/core_string_names.h" +#include "editor/audio_stream_preview.h" +#include "editor/editor_scale.h" +#include "editor/editor_settings.h" +#include "scene/resources/audio_stream_wav.h" + +// AudioStreamEditor + +void AudioStreamEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + AudioStreamPreviewGenerator::get_singleton()->connect(SNAME("preview_updated"), callable_mp(this, &AudioStreamEditor::_preview_changed)); + } break; + case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_ENTER_TREE: { + Ref<Font> font = get_theme_font(SNAME("status_source"), SNAME("EditorFonts")); + + _current_label->add_theme_font_override(SNAME("font"), font); + _duration_label->add_theme_font_override(SNAME("font"), font); + + _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); + _stop_button->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); + _preview->set_color(get_theme_color(SNAME("dark_color_2"), SNAME("Editor"))); + + set_color(get_theme_color(SNAME("dark_color_1"), SNAME("Editor"))); + + _indicator->queue_redraw(); + _preview->queue_redraw(); + } break; + case NOTIFICATION_PROCESS: { + _current = _player->get_playback_position(); + _indicator->queue_redraw(); + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (!is_visible_in_tree()) { + _stop(); + } + } break; + default: { + } break; + } +} + +void AudioStreamEditor::_draw_preview() { + Rect2 rect = _preview->get_rect(); + Size2 size = get_size(); + + Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream); + float preview_len = preview->get_length(); + + Vector<Vector2> lines; + lines.resize(size.width * 2); + + for (int i = 0; i < size.width; i++) { + float ofs = i * preview_len / size.width; + float ofs_n = (i + 1) * preview_len / size.width; + float max = preview->get_max(ofs, ofs_n) * 0.5 + 0.5; + float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5; + + int idx = i; + lines.write[idx * 2 + 0] = Vector2(i + 1, rect.position.y + min * rect.size.y); + lines.write[idx * 2 + 1] = Vector2(i + 1, rect.position.y + max * rect.size.y); + } + + RS::get_singleton()->canvas_item_add_multiline(_preview->get_canvas_item(), lines, { get_theme_color(SNAME("contrast_color_2"), SNAME("Editor")) }); +} + +void AudioStreamEditor::_preview_changed(ObjectID p_which) { + if (stream.is_valid() && stream->get_instance_id() == p_which) { + _preview->queue_redraw(); + } +} + +void AudioStreamEditor::_stream_changed() { + if (!is_visible()) { + return; + } + queue_redraw(); +} + +void AudioStreamEditor::_play() { + if (_player->is_playing()) { + _pausing = true; + _player->stop(); + _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); + set_process(false); + } else { + _pausing = false; + _player->play(_current); + _play_button->set_icon(get_theme_icon(SNAME("Pause"), SNAME("EditorIcons"))); + set_process(true); + } +} + +void AudioStreamEditor::_stop() { + _player->stop(); + _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); + _current = 0; + _indicator->queue_redraw(); + set_process(false); +} + +void AudioStreamEditor::_on_finished() { + _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); + if (!_pausing) { + _current = 0; + _indicator->queue_redraw(); + } else { + _pausing = false; + } + set_process(false); +} + +void AudioStreamEditor::_draw_indicator() { + if (stream.is_null()) { + return; + } + + Rect2 rect = _preview->get_rect(); + float len = stream->get_length(); + float ofs_x = _current / len * rect.size.width; + const Color col = get_theme_color(SNAME("accent_color"), SNAME("Editor")); + Ref<Texture2D> icon = get_theme_icon(SNAME("TimelineIndicator"), SNAME("EditorIcons")); + _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), col, Math::round(2 * EDSCALE)); + _indicator->draw_texture( + icon, + Point2(ofs_x - icon->get_width() * 0.5, 0), + col); + + _current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /"); +} + +void AudioStreamEditor::_on_input_indicator(Ref<InputEvent> p_event) { + const Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) { + if (mb->is_pressed()) { + _seek_to(mb->get_position().x); + } + _dragging = mb->is_pressed(); + } + + const Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + if (_dragging) { + _seek_to(mm->get_position().x); + } + } +} + +void AudioStreamEditor::_seek_to(real_t p_x) { + _current = p_x / _preview->get_rect().size.x * stream->get_length(); + _current = CLAMP(_current, 0, stream->get_length()); + _player->seek(_current); + _indicator->queue_redraw(); +} + +void AudioStreamEditor::set_stream(const Ref<AudioStream> &p_stream) { + if (stream.is_valid()) { + stream->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &AudioStreamEditor::_stream_changed)); + } + + stream = p_stream; + if (stream.is_null()) { + hide(); + return; + } + stream->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &AudioStreamEditor::_stream_changed)); + + _player->set_stream(stream); + _current = 0; + + String text = String::num(stream->get_length(), 2).pad_decimals(2) + "s"; + _duration_label->set_text(text); + + queue_redraw(); +} + +AudioStreamEditor::AudioStreamEditor() { + set_custom_minimum_size(Size2(1, 100) * EDSCALE); + + _player = memnew(AudioStreamPlayer); + _player->connect(SNAME("finished"), callable_mp(this, &AudioStreamEditor::_on_finished)); + add_child(_player); + + VBoxContainer *vbox = memnew(VBoxContainer); + vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); + add_child(vbox); + + _preview = memnew(ColorRect); + _preview->set_v_size_flags(SIZE_EXPAND_FILL); + _preview->connect(SNAME("draw"), callable_mp(this, &AudioStreamEditor::_draw_preview)); + vbox->add_child(_preview); + + _indicator = memnew(Control); + _indicator->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); + _indicator->connect(SNAME("draw"), callable_mp(this, &AudioStreamEditor::_draw_indicator)); + _indicator->connect(SNAME("gui_input"), callable_mp(this, &AudioStreamEditor::_on_input_indicator)); + _preview->add_child(_indicator); + + HBoxContainer *hbox = memnew(HBoxContainer); + hbox->add_theme_constant_override("separation", 0); + vbox->add_child(hbox); + + _play_button = memnew(Button); + hbox->add_child(_play_button); + _play_button->set_flat(true); + _play_button->set_focus_mode(Control::FOCUS_NONE); + _play_button->connect(SNAME("pressed"), callable_mp(this, &AudioStreamEditor::_play)); + _play_button->set_shortcut(ED_SHORTCUT("audio_stream_editor/audio_preview_play_pause", TTR("Audio Preview Play/Pause"), Key::SPACE)); + + _stop_button = memnew(Button); + hbox->add_child(_stop_button); + _stop_button->set_flat(true); + _stop_button->set_focus_mode(Control::FOCUS_NONE); + _stop_button->connect(SNAME("pressed"), callable_mp(this, &AudioStreamEditor::_stop)); + + _current_label = memnew(Label); + _current_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); + _current_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + _current_label->set_modulate(Color(1, 1, 1, 0.5)); + hbox->add_child(_current_label); + + _duration_label = memnew(Label); + hbox->add_child(_duration_label); +} + +// EditorInspectorPluginAudioStream + +bool EditorInspectorPluginAudioStream::can_handle(Object *p_object) { + return Object::cast_to<AudioStreamWAV>(p_object) != nullptr; +} + +void EditorInspectorPluginAudioStream::parse_begin(Object *p_object) { + AudioStream *stream = Object::cast_to<AudioStream>(p_object); + + editor = memnew(AudioStreamEditor); + editor->set_stream(Ref<AudioStream>(stream)); + + add_custom_control(editor); +} + +// AudioStreamEditorPlugin + +AudioStreamEditorPlugin::AudioStreamEditorPlugin() { + Ref<EditorInspectorPluginAudioStream> plugin; + plugin.instantiate(); + add_inspector_plugin(plugin); +} diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h new file mode 100644 index 0000000000..13e52929ee --- /dev/null +++ b/editor/plugins/audio_stream_editor_plugin.h @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* audio_stream_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef AUDIO_STREAM_EDITOR_PLUGIN_H +#define AUDIO_STREAM_EDITOR_PLUGIN_H + +#include "editor/editor_inspector.h" +#include "editor/editor_plugin.h" +#include "scene/audio/audio_stream_player.h" +#include "scene/gui/button.h" +#include "scene/gui/color_rect.h" +#include "scene/gui/label.h" + +class AudioStreamEditor : public ColorRect { + GDCLASS(AudioStreamEditor, ColorRect); + + Ref<AudioStream> stream; + + AudioStreamPlayer *_player = nullptr; + ColorRect *_preview = nullptr; + Control *_indicator = nullptr; + Label *_current_label = nullptr; + Label *_duration_label = nullptr; + + Button *_play_button = nullptr; + Button *_stop_button = nullptr; + + float _current = 0; + bool _dragging = false; + bool _pausing = false; + +protected: + void _notification(int p_what); + void _preview_changed(ObjectID p_which); + void _play(); + void _stop(); + void _on_finished(); + void _draw_preview(); + void _draw_indicator(); + void _on_input_indicator(Ref<InputEvent> p_event); + void _seek_to(real_t p_x); + void _stream_changed(); + +public: + void set_stream(const Ref<AudioStream> &p_stream); + + AudioStreamEditor(); +}; + +class EditorInspectorPluginAudioStream : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginAudioStream, EditorInspectorPlugin); + AudioStreamEditor *editor = nullptr; + +public: + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; +}; + +class AudioStreamEditorPlugin : public EditorPlugin { + GDCLASS(AudioStreamEditorPlugin, EditorPlugin); + +public: + AudioStreamEditorPlugin(); +}; + +#endif // AUDIO_STREAM_EDITOR_PLUGIN_H diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp index e21a50a434..61b7683a05 100644 --- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp +++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp @@ -81,7 +81,7 @@ void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_und if (p_from_index < 0) { undo_redo_man->add_undo_method(randomizer, "remove_stream", p_to_pos < 0 ? randomizer->get_streams_count() : p_to_pos); } else if (p_to_pos < 0) { - undo_redo_man->add_undo_method(randomizer, "add_stream", p_from_index); + undo_redo_man->add_undo_method(randomizer, "add_stream", p_from_index, Ref<AudioStream>()); } List<PropertyInfo> properties; @@ -107,7 +107,7 @@ void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_und #undef ADD_UNDO if (p_from_index < 0) { - undo_redo_man->add_do_method(randomizer, "add_stream", p_to_pos); + undo_redo_man->add_do_method(randomizer, "add_stream", p_to_pos, Ref<AudioStream>()); } else if (p_to_pos < 0) { undo_redo_man->add_do_method(randomizer, "remove_stream", p_from_index); } else { diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index efb2c80cfd..0f8ed1c857 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/editor/plugins/editor_preview_plugins.h @@ -70,10 +70,12 @@ public: }; class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator { + GDCLASS(EditorPackedScenePreviewPlugin, EditorResourcePreviewGenerator); + public: - virtual bool handles(const String &p_type) const; - virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const; - virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override; + virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size) const override; EditorPackedScenePreviewPlugin(); }; @@ -107,17 +109,21 @@ public: }; class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator { + GDCLASS(EditorScriptPreviewPlugin, EditorResourcePreviewGenerator); + public: - virtual bool handles(const String &p_type) const; - virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override; EditorScriptPreviewPlugin(); }; class EditorAudioStreamPreviewPlugin : public EditorResourcePreviewGenerator { + GDCLASS(EditorAudioStreamPreviewPlugin, EditorResourcePreviewGenerator); + public: - virtual bool handles(const String &p_type) const; - virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override; EditorAudioStreamPreviewPlugin(); }; diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp index 4370d013be..6b3db095d4 100644 --- a/editor/plugins/font_config_plugin.cpp +++ b/editor/plugins/font_config_plugin.cpp @@ -483,7 +483,7 @@ void EditorPropertyOTVariation::update_property() { Vector3i range = supported.get_value_at_index(i); EditorPropertyInteger *prop = memnew(EditorPropertyInteger); - prop->setup(range.x, range.y, 1, false, false); + prop->setup(range.x, range.y, false, 1, false, false); prop->set_object_and_property(object.ptr(), "keys/" + itos(name_tag)); String name = TS->tag_to_name(name_tag); @@ -762,7 +762,7 @@ void EditorPropertyOTFeatures::update_property() { } break; case Variant::INT: { EditorPropertyInteger *editor = memnew(EditorPropertyInteger); - editor->setup(0, 255, 1, false, false); + editor->setup(0, 255, 1, false, false, false); prop = editor; } break; default: { diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 4a8e5d9979..4b31e99f0e 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -160,23 +160,23 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, p_library->set_item_shapes(id, collisions); - Ref<NavigationMesh> navmesh; - Transform3D navmesh_transform; + Ref<NavigationMesh> navigation_mesh; + Transform3D navigation_mesh_transform; for (int j = 0; j < mi->get_child_count(); j++) { Node *child2 = mi->get_child(j); if (!Object::cast_to<NavigationRegion3D>(child2)) { continue; } NavigationRegion3D *sb = Object::cast_to<NavigationRegion3D>(child2); - navmesh = sb->get_navigation_mesh(); - navmesh_transform = sb->get_transform(); - if (!navmesh.is_null()) { + navigation_mesh = sb->get_navigation_mesh(); + navigation_mesh_transform = sb->get_transform(); + if (!navigation_mesh.is_null()) { break; } } - if (!navmesh.is_null()) { - p_library->set_item_navmesh(id, navmesh); - p_library->set_item_navmesh_transform(id, navmesh_transform); + if (!navigation_mesh.is_null()) { + p_library->set_item_navigation_mesh(id, navigation_mesh); + p_library->set_item_navigation_mesh_transform(id, navigation_mesh_transform); } } diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 363ad273a8..4976c8c750 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -2606,7 +2606,7 @@ void Node3DEditorViewport::_project_settings_changed() { const bool use_taa = GLOBAL_GET("rendering/anti_aliasing/quality/use_taa"); viewport->set_use_taa(use_taa); - const bool transparent_background = GLOBAL_GET("rendering/transparent_background"); + const bool transparent_background = GLOBAL_GET("rendering/viewport/transparent_background"); viewport->set_transparent_background(transparent_background); const bool use_debanding = GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding"); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index f79a001efb..d2dadd884b 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -153,9 +153,10 @@ void BoneTransformEditor::set_target(const String &p_prop) { void BoneTransformEditor::_property_keyed(const String &p_path, bool p_advance) { AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor(); - if (!te->has_keying()) { + if (!te || !te->has_keying()) { return; } + te->_clear_selection(); PackedStringArray split = p_path.split("/"); if (split.size() == 3 && split[0] == "bones") { int bone_idx = split[1].to_int(); diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 57f9b3135a..1fdf940a82 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -309,7 +309,22 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { case ROTATE_LEFT: case FLIP_HORIZONTALLY: case FLIP_VERTICALLY: { - undo_redo->create_action(TTR("Rotate Polygons Left")); + switch (p_item_pressed) { + case ROTATE_RIGHT: { + undo_redo->create_action(TTR("Rotate Polygons Right")); + } break; + case ROTATE_LEFT: { + undo_redo->create_action(TTR("Rotate Polygons Left")); + } break; + case FLIP_HORIZONTALLY: { + undo_redo->create_action(TTR("Flip Polygons Horizontally")); + } break; + case FLIP_VERTICALLY: { + undo_redo->create_action(TTR("Flip Polygons Vertically")); + } break; + default: + break; + } for (unsigned int i = 0; i < polygons.size(); i++) { Vector<Point2> new_polygon; for (int point_index = 0; point_index < polygons[i].size(); point_index++) { diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 4131c06745..5a1f214933 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -924,6 +924,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over Color modulate = tile_data->get_modulate(); Color self_modulate = tile_map->get_self_modulate(); modulate *= self_modulate; + modulate *= tile_map->get_layer_modulate(tile_map_layer); // Draw the tile. p_overlay->draw_texture_rect_region(atlas_source->get_texture(), dest_rect, source_rect, modulate * Color(1.0, 1.0, 1.0, 0.5), transpose, tile_set->is_uv_clipping()); diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index b31fb1aa58..2868c14452 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -398,7 +398,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() { source_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed)); source_from_property_editor->set_selectable(false); source_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); - source_from_property_editor->setup(-1, 99999, 1, true, false); + source_from_property_editor->setup(-1, 99999, 1, false, true, false); vboxcontainer_from->add_child(source_from_property_editor); coords_from_property_editor = memnew(EditorPropertyVector2i); @@ -417,7 +417,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() { alternative_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed)); alternative_from_property_editor->set_selectable(false); alternative_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); - alternative_from_property_editor->setup(-1, 99999, 1, true, false); + alternative_from_property_editor->setup(-1, 99999, 1, false, true, false); alternative_from_property_editor->hide(); vboxcontainer_from->add_child(alternative_from_property_editor); @@ -432,7 +432,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() { source_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed)); source_to_property_editor->set_selectable(false); source_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); - source_to_property_editor->setup(-1, 99999, 1, true, false); + source_to_property_editor->setup(-1, 99999, 1, false, true, false); vboxcontainer_to->add_child(source_to_property_editor); coords_to_property_editor = memnew(EditorPropertyVector2i); @@ -451,7 +451,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() { alternative_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed)); alternative_to_property_editor->set_selectable(false); alternative_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); - alternative_to_property_editor->setup(-1, 99999, 1, true, false); + alternative_to_property_editor->setup(-1, 99999, 1, false, true, false); alternative_to_property_editor->hide(); vboxcontainer_to->add_child(alternative_to_property_editor); diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 369a59c443..e9c6184d73 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -47,43 +47,7 @@ VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr; void VersionControlEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("_initialize_vcs"), &VersionControlEditorPlugin::_initialize_vcs); - ClassDB::bind_method(D_METHOD("_set_credentials"), &VersionControlEditorPlugin::_set_credentials); - ClassDB::bind_method(D_METHOD("_update_set_up_warning"), &VersionControlEditorPlugin::_update_set_up_warning); - ClassDB::bind_method(D_METHOD("_commit"), &VersionControlEditorPlugin::_commit); - ClassDB::bind_method(D_METHOD("_refresh_stage_area"), &VersionControlEditorPlugin::_refresh_stage_area); - ClassDB::bind_method(D_METHOD("_move_all"), &VersionControlEditorPlugin::_move_all); - ClassDB::bind_method(D_METHOD("_load_diff"), &VersionControlEditorPlugin::_load_diff); - ClassDB::bind_method(D_METHOD("_display_diff"), &VersionControlEditorPlugin::_display_diff); - ClassDB::bind_method(D_METHOD("_item_activated"), &VersionControlEditorPlugin::_item_activated); - ClassDB::bind_method(D_METHOD("_update_branch_create_button"), &VersionControlEditorPlugin::_update_branch_create_button); - ClassDB::bind_method(D_METHOD("_update_remote_create_button"), &VersionControlEditorPlugin::_update_remote_create_button); - ClassDB::bind_method(D_METHOD("_update_commit_button"), &VersionControlEditorPlugin::_update_commit_button); - ClassDB::bind_method(D_METHOD("_refresh_branch_list"), &VersionControlEditorPlugin::_refresh_branch_list); - ClassDB::bind_method(D_METHOD("_set_commit_list_size"), &VersionControlEditorPlugin::_set_commit_list_size); - ClassDB::bind_method(D_METHOD("_refresh_commit_list"), &VersionControlEditorPlugin::_refresh_commit_list); - ClassDB::bind_method(D_METHOD("_refresh_remote_list"), &VersionControlEditorPlugin::_refresh_remote_list); - ClassDB::bind_method(D_METHOD("_ssh_public_key_selected"), &VersionControlEditorPlugin::_ssh_public_key_selected); - ClassDB::bind_method(D_METHOD("_ssh_private_key_selected"), &VersionControlEditorPlugin::_ssh_private_key_selected); - ClassDB::bind_method(D_METHOD("_commit_message_gui_input"), &VersionControlEditorPlugin::_commit_message_gui_input); - ClassDB::bind_method(D_METHOD("_cell_button_pressed"), &VersionControlEditorPlugin::_cell_button_pressed); - ClassDB::bind_method(D_METHOD("_discard_all"), &VersionControlEditorPlugin::_discard_all); - ClassDB::bind_method(D_METHOD("_create_branch"), &VersionControlEditorPlugin::_create_branch); - ClassDB::bind_method(D_METHOD("_create_remote"), &VersionControlEditorPlugin::_create_remote); - ClassDB::bind_method(D_METHOD("_remove_branch"), &VersionControlEditorPlugin::_remove_branch); - ClassDB::bind_method(D_METHOD("_remove_remote"), &VersionControlEditorPlugin::_remove_remote); - ClassDB::bind_method(D_METHOD("_branch_item_selected"), &VersionControlEditorPlugin::_branch_item_selected); - ClassDB::bind_method(D_METHOD("_remote_selected"), &VersionControlEditorPlugin::_remote_selected); - ClassDB::bind_method(D_METHOD("_fetch"), &VersionControlEditorPlugin::_fetch); - ClassDB::bind_method(D_METHOD("_pull"), &VersionControlEditorPlugin::_pull); - ClassDB::bind_method(D_METHOD("_push"), &VersionControlEditorPlugin::_push); - ClassDB::bind_method(D_METHOD("_extra_option_selected"), &VersionControlEditorPlugin::_extra_option_selected); - ClassDB::bind_method(D_METHOD("_update_extra_options"), &VersionControlEditorPlugin::_update_extra_options); - ClassDB::bind_method(D_METHOD("_popup_branch_remove_confirm"), &VersionControlEditorPlugin::_popup_branch_remove_confirm); - ClassDB::bind_method(D_METHOD("_popup_remote_remove_confirm"), &VersionControlEditorPlugin::_popup_remote_remove_confirm); - ClassDB::bind_method(D_METHOD("_popup_file_dialog"), &VersionControlEditorPlugin::_popup_file_dialog); - - ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog); + // No binds required so far. } void VersionControlEditorPlugin::_create_vcs_metadata_files() { @@ -94,12 +58,10 @@ void VersionControlEditorPlugin::_create_vcs_metadata_files() { void VersionControlEditorPlugin::_notification(int p_what) { if (p_what == NOTIFICATION_READY) { String installed_plugin = GLOBAL_DEF("editor/version_control/plugin_name", ""); - String project_path = GLOBAL_DEF("editor/version_control/project_path", OS::get_singleton()->get_resource_dir()); - project_path_input->set_text(project_path); bool has_autoload_enable = GLOBAL_DEF("editor/version_control/autoload_on_startup", false); if (installed_plugin != "" && has_autoload_enable) { - if (_load_plugin(installed_plugin, project_path)) { + if (_load_plugin(installed_plugin)) { _set_credentials(); } } @@ -144,18 +106,15 @@ void VersionControlEditorPlugin::_initialize_vcs() { const int id = set_up_choice->get_selected_id(); String selected_plugin = set_up_choice->get_item_text(id); - if (_load_plugin(selected_plugin, project_path_input->get_text())) { + if (_load_plugin(selected_plugin)) { ProjectSettings::get_singleton()->set("editor/version_control/autoload_on_startup", true); ProjectSettings::get_singleton()->set("editor/version_control/plugin_name", selected_plugin); - ProjectSettings::get_singleton()->set("editor/version_control/project_path", project_path_input->get_text()); ProjectSettings::get_singleton()->save(); } } void VersionControlEditorPlugin::_set_vcs_ui_state(bool p_enabled) { - select_project_path_button->set_disabled(p_enabled); set_up_dialog->get_ok_button()->set_disabled(!p_enabled); - project_path_input->set_editable(!p_enabled); set_up_choice->set_disabled(p_enabled); toggle_vcs_choice->set_pressed_no_signal(p_enabled); } @@ -181,14 +140,14 @@ void VersionControlEditorPlugin::_set_credentials() { EditorSettings::get_singleton()->set_setting("version_control/ssh_private_key_path", ssh_private_key); } -bool VersionControlEditorPlugin::_load_plugin(String p_name, String p_project_path) { +bool VersionControlEditorPlugin::_load_plugin(String p_name) { Object *extension_instance = ClassDB::instantiate(p_name); ERR_FAIL_NULL_V_MSG(extension_instance, false, "Received a nullptr VCS extension instance during construction."); EditorVCSInterface *vcs_plugin = Object::cast_to<EditorVCSInterface>(extension_instance); ERR_FAIL_NULL_V_MSG(vcs_plugin, false, vformat("Could not cast VCS extension instance to %s.", EditorVCSInterface::get_class_static())); - String res_dir = project_path_input->get_text(); + String res_dir = OS::get_singleton()->get_resource_dir(); ERR_FAIL_COND_V_MSG(!vcs_plugin->initialize(res_dir), false, "Could not initialize " + p_name); @@ -435,6 +394,10 @@ void VersionControlEditorPlugin::_discard_file(String p_file_path, EditorVCSInte EditorFileSystem::get_singleton()->update_file(p_file_path); } +void VersionControlEditorPlugin::_confirm_discard_all() { + discard_all_confirm->popup_centered(); +} + void VersionControlEditorPlugin::_discard_all() { TreeItem *file_entry = unstaged_files->get_root()->get_first_child(); while (file_entry) { @@ -631,7 +594,6 @@ void VersionControlEditorPlugin::_display_diff(int p_idx) { diff->pop(); diff->pop(); - diff->add_newline(); diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("status_source"), SNAME("EditorFonts"))); for (int j = 0; j < diff_file.diff_hunks.size(); j++) { EditorVCSInterface::DiffHunk hunk = diff_file.diff_hunks[j]; @@ -641,6 +603,7 @@ void VersionControlEditorPlugin::_display_diff(int p_idx) { String old_lines = String::num_int64(hunk.old_lines); String new_lines = String::num_int64(hunk.new_lines); + diff->add_newline(); diff->append_text("[center]@@ " + old_start + "," + old_lines + " " + new_start + "," + new_lines + " @@[/center]"); diff->add_newline(); @@ -653,7 +616,6 @@ void VersionControlEditorPlugin::_display_diff(int p_idx) { break; } diff->add_newline(); - diff->add_newline(); } diff->pop(); @@ -721,12 +683,10 @@ void VersionControlEditorPlugin::_display_diff_split_view(List<EditorVCSInterfac if (diff_line.old_line_no >= 0) { diff->push_cell(); - diff->push_indent(1); diff->push_color(has_change ? red : white); diff->add_text(String::num_int64(diff_line.old_line_no)); diff->pop(); diff->pop(); - diff->pop(); diff->push_cell(); diff->push_color(has_change ? red : white); @@ -753,12 +713,10 @@ void VersionControlEditorPlugin::_display_diff_split_view(List<EditorVCSInterfac if (diff_line.new_line_no >= 0) { diff->push_cell(); - diff->push_indent(1); diff->push_color(has_change ? green : white); diff->add_text(String::num_int64(diff_line.new_line_no)); diff->pop(); diff->pop(); - diff->pop(); diff->push_cell(); diff->push_color(has_change ? green : white); @@ -943,10 +901,6 @@ void VersionControlEditorPlugin::_toggle_vcs_integration(bool p_toggled) { } } -void VersionControlEditorPlugin::_project_path_selected(String p_project_path) { - project_path_input->set_text(p_project_path); -} - void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() { available_plugins.clear(); ClassDB::get_direct_inheriters_from_class(EditorVCSInterface::get_class_static(), &available_plugins); @@ -1040,34 +994,6 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { set_up_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL); set_up_hbc->add_child(set_up_choice); - HBoxContainer *project_path_hbc = memnew(HBoxContainer); - project_path_hbc->set_h_size_flags(Control::SIZE_FILL); - set_up_vbc->add_child(project_path_hbc); - - Label *project_path_label = memnew(Label); - project_path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); - project_path_label->set_text(TTR("VCS Project Path")); - project_path_hbc->add_child(project_path_label); - - project_path_input = memnew(LineEdit); - project_path_input->set_h_size_flags(Control::SIZE_EXPAND_FILL); - project_path_input->set_text(OS::get_singleton()->get_resource_dir()); - project_path_hbc->add_child(project_path_input); - - FileDialog *select_project_path_file_dialog = memnew(FileDialog); - select_project_path_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM); - select_project_path_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR); - select_project_path_file_dialog->set_show_hidden_files(true); - select_project_path_file_dialog->set_current_dir(OS::get_singleton()->get_resource_dir()); - select_project_path_file_dialog->connect(SNAME("dir_selected"), callable_mp(this, &VersionControlEditorPlugin::_project_path_selected)); - project_path_hbc->add_child(select_project_path_file_dialog); - - select_project_path_button = memnew(Button); - select_project_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons")); - select_project_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(select_project_path_file_dialog)); - select_project_path_button->set_tooltip_text(TTR("Select VCS project path")); - project_path_hbc->add_child(select_project_path_button); - HBoxContainer *toggle_vcs_hbc = memnew(HBoxContainer); toggle_vcs_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); set_up_vbc->add_child(toggle_vcs_hbc); @@ -1240,10 +1166,21 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list)); unstage_title->add_child(refresh_button); + discard_all_confirm = memnew(AcceptDialog); + discard_all_confirm->set_title(TTR("Discard all changes")); + discard_all_confirm->set_min_size(Size2i(400, 50)); + discard_all_confirm->set_text(TTR("This operation is IRREVERSIBLE. Your changes will be deleted FOREVER.")); + discard_all_confirm->set_hide_on_ok(true); + discard_all_confirm->set_ok_button_text(TTR("Permanentally delete my changes")); + discard_all_confirm->add_cancel_button(); + version_commit_dock->add_child(discard_all_confirm); + + discard_all_confirm->get_ok_button()->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_discard_all)); + discard_all_button = memnew(Button); discard_all_button->set_tooltip_text(TTR("Discard all changes")); discard_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Close"), SNAME("EditorIcons"))); - discard_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_discard_all)); + discard_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_confirm_discard_all)); discard_all_button->set_flat(true); unstage_title->add_child(discard_all_button); diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h index 3340384a92..d73588a1bf 100644 --- a/editor/plugins/version_control_editor_plugin.h +++ b/editor/plugins/version_control_editor_plugin.h @@ -73,8 +73,6 @@ private: AcceptDialog *set_up_dialog = nullptr; CheckButton *toggle_vcs_choice = nullptr; OptionButton *set_up_choice = nullptr; - LineEdit *project_path_input = nullptr; - Button *select_project_path_button = nullptr; VBoxContainer *set_up_vbc = nullptr; VBoxContainer *set_up_settings_vbc = nullptr; LineEdit *set_up_username = nullptr; @@ -86,6 +84,8 @@ private: FileDialog *set_up_ssh_private_key_file_dialog = nullptr; Label *set_up_warning_text = nullptr; + AcceptDialog *discard_all_confirm = nullptr; + OptionButton *commit_list_size_button = nullptr; AcceptDialog *branch_create_confirm = nullptr; @@ -150,13 +150,14 @@ private: void _update_opened_tabs(); void _update_extra_options(); - bool _load_plugin(String p_name, String p_project_path); + bool _load_plugin(String p_name); void _pull(); void _push(); void _force_push(); void _fetch(); void _commit(); + void _confirm_discard_all(); void _discard_all(); void _refresh_stage_area(); void _refresh_branch_list(); @@ -193,7 +194,6 @@ private: void _create_vcs_metadata_files(); void _popup_file_dialog(Variant p_file_dialog_variant); void _toggle_vcs_integration(bool p_toggled); - void _project_path_selected(String p_project_path); friend class EditorVCSInterface; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index cf811067c9..c93b0019dc 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1263,7 +1263,7 @@ Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) { Ref<Script> scr = Ref<Script>(p_resource.ptr()); - if (scr.is_null() || scr->get_instance_base_type() != String("VisualShaderNodeCustom")) { + if (scr.is_null() || scr->get_instance_base_type() != "VisualShaderNodeCustom") { return; } diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 1b169076c6..0d93c8a95e 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -447,7 +447,7 @@ private: } else if (renderer_type == "gl_compatibility") { renderer_info->set_text( String::utf8("• ") + TTR("Supports desktop, mobile + web platforms.") + - String::utf8("\n• ") + TTR("Least advanced 3D graphics.") + + String::utf8("\n• ") + TTR("Least advanced 3D graphics (currently work-in-progress).") + String::utf8("\n• ") + TTR("Intended for low-end/older devices.") + String::utf8("\n• ") + TTR("Uses OpenGL 3 backend (OpenGL 3.3/ES 3.0/WebGL2).") + String::utf8("\n• ") + TTR("Fastest rendering of simple scenes.")); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index b406b2a1ce..b99a83a546 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -553,6 +553,14 @@ void ProjectSettingsEditor::_update_theme() { } } +void ProjectSettingsEditor::_input_filter_focused() { + set_close_on_escape(false); +} + +void ProjectSettingsEditor::_input_filter_unfocused() { + set_close_on_escape(true); +} + void ProjectSettingsEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { @@ -683,6 +691,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { action_map_editor->connect("action_removed", callable_mp(this, &ProjectSettingsEditor::_action_removed)); action_map_editor->connect("action_renamed", callable_mp(this, &ProjectSettingsEditor::_action_renamed)); action_map_editor->connect("action_reordered", callable_mp(this, &ProjectSettingsEditor::_action_reordered)); + action_map_editor->connect(SNAME("filter_focused"), callable_mp(this, &ProjectSettingsEditor::_input_filter_focused)); + action_map_editor->connect(SNAME("filter_unfocused"), callable_mp(this, &ProjectSettingsEditor::_input_filter_unfocused)); tab_container->add_child(action_map_editor); localization_editor = memnew(LocalizationEditor); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index 7f6dd1b692..1687be47fb 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -107,6 +107,9 @@ class ProjectSettingsEditor : public AcceptDialog { void _update_action_map_editor(); void _update_theme(); + void _input_filter_focused(); + void _input_filter_unfocused(); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index 247d5e1717..8ac0aa6fe3 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -48,6 +48,7 @@ #include "editor/import/editor_import_plugin.h" #include "editor/import/resource_importer_scene.h" #include "editor/plugins/animation_tree_editor_plugin.h" +#include "editor/plugins/audio_stream_editor_plugin.h" #include "editor/plugins/audio_stream_randomizer_editor_plugin.h" #include "editor/plugins/bit_map_editor_plugin.h" #include "editor/plugins/bone_map_editor_plugin.h" @@ -155,6 +156,7 @@ void register_editor_types() { // This list is alphabetized, and plugins that depend on Node2D are in their own section below. EditorPlugins::add_by_type<AnimationTreeEditorPlugin>(); + EditorPlugins::add_by_type<AudioStreamEditorPlugin>(); EditorPlugins::add_by_type<AudioStreamRandomizerEditorPlugin>(); EditorPlugins::add_by_type<BitMapEditorPlugin>(); EditorPlugins::add_by_type<BoneMapEditorPlugin>(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 96688a3614..f91b571118 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1965,37 +1965,21 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { } Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - if (selected.size() == 1) { - Node *node = selected.front()->get(); - Ref<Script> existing = node->get_script(); - - undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, node); - undo_redo->add_do_method(InspectorDock::get_singleton(), "store_script_properties", node); - undo_redo->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node); - undo_redo->add_do_method(node, "set_script", p_script); - undo_redo->add_undo_method(node, "set_script", existing); - undo_redo->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node); - undo_redo->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node); + undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, selected.front()->get()); + for (Node *E : selected) { + Ref<Script> existing = E->get_script(); + undo_redo->add_do_method(InspectorDock::get_singleton(), "store_script_properties", E); + undo_redo->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E); + undo_redo->add_do_method(E, "set_script", p_script); + undo_redo->add_undo_method(E, "set_script", existing); + undo_redo->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E); + undo_redo->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E); undo_redo->add_do_method(this, "_update_script_button"); undo_redo->add_undo_method(this, "_update_script_button"); - undo_redo->commit_action(); - } else { - undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, selected.front()->get()); - for (Node *E : selected) { - Ref<Script> existing = E->get_script(); - undo_redo->add_do_method(InspectorDock::get_singleton(), "store_script_properties", E); - undo_redo->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E); - undo_redo->add_do_method(E, "set_script", p_script); - undo_redo->add_undo_method(E, "set_script", existing); - undo_redo->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E); - undo_redo->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E); - undo_redo->add_do_method(this, "_update_script_button"); - undo_redo->add_undo_method(this, "_update_script_button"); - } - undo_redo->commit_action(); } + undo_redo->commit_action(); - _push_item(p_script.operator->()); + _push_item(p_script.ptr()); _update_script_button(); } diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index 155f7809b0..8d21541341 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -277,6 +277,7 @@ void initialize_basis_universal_module(ModuleInitializationLevel p_level) { basisu_encoder_init(); Image::basis_universal_packer = basis_universal_packer; #endif + basist::basisu_transcoder_init(); Image::basis_universal_unpacker = basis_universal_unpacker; Image::basis_universal_unpacker_ptr = basis_universal_unpacker_ptr; } diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 4981750b7d..fd748ea569 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -106,6 +106,7 @@ <param index="0" name="instance" type="Object" /> <description> Returns the passed [param instance] converted to a Dictionary. Can be useful for serializing. + [b]Note:[/b] Cannot be used to serialize objects with built-in scripts attached or objects allocated within built-in scripts. [codeblock] var foo = "bar" func _ready(): diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 258f1a80f7..1fe1561559 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1111,21 +1111,27 @@ bool GDScript::inherits_script(const Ref<Script> &p_script) const { GDScript *GDScript::find_class(const String &p_qualified_name) { String first = p_qualified_name.get_slice("::", 0); + Vector<String> class_names; GDScript *result = nullptr; + // Empty initial name means start here. if (first.is_empty() || first == name) { + class_names = p_qualified_name.split("::"); result = this; - } else if (first == get_root_script()->path) { + } else if (p_qualified_name.begins_with(get_root_script()->path)) { + // Script path could have a class path separator("::") in it. + class_names = p_qualified_name.trim_prefix(get_root_script()->path).split("::"); result = get_root_script(); } else if (HashMap<StringName, Ref<GDScript>>::Iterator E = subclasses.find(first)) { + class_names = p_qualified_name.split("::"); result = E->value.ptr(); } else if (_owner != nullptr) { // Check parent scope. return _owner->find_class(p_qualified_name); } - int name_count = p_qualified_name.get_slice_count("::"); - for (int i = 1; result != nullptr && i < name_count; i++) { - String current_name = p_qualified_name.get_slice("::", i); + // Starts at index 1 because index 0 was handled above. + for (int i = 1; result != nullptr && i < class_names.size(); i++) { + String current_name = class_names[i]; if (HashMap<StringName, Ref<GDScript>>::Iterator E = result->subclasses.find(current_name)) { result = E->value.ptr(); } else { @@ -1137,11 +1143,12 @@ GDScript *GDScript::find_class(const String &p_qualified_name) { return result; } -bool GDScript::is_subclass(const GDScript *p_script) { +bool GDScript::has_class(const GDScript *p_script) { String fqn = p_script->fully_qualified_name; - if (!fqn.is_empty() && fqn != fully_qualified_name && fqn.begins_with(fully_qualified_name)) { - String fqn_rest = fqn.substr(fully_qualified_name.length()); - return find_class(fqn_rest) == p_script; + if (fully_qualified_name.is_empty() && fqn.get_slice("::", 0).is_empty()) { + return p_script == this; + } else if (fqn.begins_with(fully_qualified_name)) { + return p_script == find_class(fqn.trim_prefix(fully_qualified_name)); } return false; } @@ -1959,6 +1966,16 @@ void GDScriptLanguage::add_named_global_constant(const StringName &p_name, const named_globals[p_name] = p_value; } +Variant GDScriptLanguage::get_any_global_constant(const StringName &p_name) { + if (named_globals.has(p_name)) { + return named_globals[p_name]; + } + if (globals.has(p_name)) { + return _global_array[globals[p_name]]; + } + ERR_FAIL_V_MSG(Variant(), vformat("Could not find any global constant with name: %s.", p_name)); +} + void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) { ERR_FAIL_COND(!named_globals.has(p_name)); named_globals.erase(p_name); @@ -2592,8 +2609,7 @@ Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String SelfList<GDScript> *elem = script_list.first(); while (elem) { GDScript *scr = elem->self(); - scr = scr->find_class(p_name); - if (scr != nullptr) { + if (scr->fully_qualified_name == p_name) { return scr; } elem = elem->next(); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 7911ea47ec..39367e377b 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -187,7 +187,7 @@ public: bool inherits_script(const Ref<Script> &p_script) const override; GDScript *find_class(const String &p_qualified_name); - bool is_subclass(const GDScript *p_script); + bool has_class(const GDScript *p_script); GDScript *get_root_script(); bool is_root_script() const { return _owner == nullptr; } String get_fully_qualified_name() const { return fully_qualified_name; } @@ -455,6 +455,9 @@ public: _FORCE_INLINE_ Variant *get_global_array() { return _global_array; } _FORCE_INLINE_ const HashMap<StringName, int> &get_global_map() const { return globals; } _FORCE_INLINE_ const HashMap<StringName, Variant> &get_named_globals_map() const { return named_globals; } + // These two functions should be used when behavior needs to be consistent between in-editor and running the scene + bool has_any_global_constant(const StringName &p_name) { return named_globals.has(p_name) || globals.has(p_name); } + Variant get_any_global_constant(const StringName &p_name); _FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index a443556fd5..fc2e6e94f3 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -901,18 +901,19 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, member.signal->set_datatype(resolving_datatype); + // This is the _only_ way to declare a signal. Therefore, we can generate its + // MethodInfo inline so it's a tiny bit more efficient. + MethodInfo mi = MethodInfo(member.signal->identifier->name); + for (int j = 0; j < member.signal->parameters.size(); j++) { - GDScriptParser::DataType signal_type = resolve_datatype(member.signal->parameters[j]->datatype_specifier); - signal_type.is_meta_type = false; - member.signal->parameters[j]->set_datatype(signal_type); + GDScriptParser::ParameterNode *param = member.signal->parameters[j]; + GDScriptParser::DataType param_type = resolve_datatype(param->datatype_specifier); + param_type.is_meta_type = false; + param->set_datatype(param_type); + mi.arguments.push_back(PropertyInfo(param_type.builtin_type, param->identifier->name)); + // TODO: add signal parameter default values } - // TODO: Make MethodInfo from signal. - GDScriptParser::DataType signal_type; - signal_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - signal_type.kind = GDScriptParser::DataType::BUILTIN; - signal_type.builtin_type = Variant::SIGNAL; - - member.signal->set_datatype(signal_type); + member.signal->set_datatype(make_signal_type(mi)); // Apply annotations. for (GDScriptParser::AnnotationNode *&E : member.signal->annotations) { @@ -1747,6 +1748,12 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable type = p_variable->initializer->get_datatype(); +#ifdef DEBUG_ENABLED + if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { + parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name); + } +#endif + if (p_variable->infer_datatype) { type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; @@ -1760,11 +1767,6 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable } else { type.type_source = GDScriptParser::DataType::INFERRED; } -#ifdef DEBUG_ENABLED - if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { - parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name); - } -#endif } if (p_variable->datatype_specifier != nullptr) { @@ -1843,7 +1845,7 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant type = p_constant->initializer->get_datatype(); #ifdef DEBUG_ENABLED - if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { + if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name); } #endif @@ -2331,7 +2333,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig } #ifdef DEBUG_ENABLED - if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) { + if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.is_hard_type() && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) { parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name); } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) { parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION); @@ -3137,6 +3139,12 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod p_identifier->reduced_value = member.enum_value.value; p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; break; + case GDScriptParser::ClassNode::Member::ENUM: + if (p_base != nullptr && p_base->is_constant) { + p_identifier->is_constant = true; + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; + } + break; case GDScriptParser::ClassNode::Member::VARIABLE: p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_VARIABLE; p_identifier->variable_source = member.variable; @@ -3148,6 +3156,18 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod case GDScriptParser::ClassNode::Member::FUNCTION: p_identifier->set_datatype(make_callable_type(member.function->info)); break; + case GDScriptParser::ClassNode::Member::CLASS: + if (p_base != nullptr && p_base->is_constant) { + p_identifier->is_constant = true; + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT; + + Error err = OK; + GDScript *scr = GDScriptCache::get_full_script(base.script_path, err).ptr(); + ERR_FAIL_COND_MSG(err != OK, "Error while getting subscript full script."); + scr = scr->find_class(p_identifier->get_datatype().class_type->fqcn); + p_identifier->reduced_value = scr; + } + break; default: break; // Type already set. } @@ -3157,7 +3177,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod // TODO: Allow outer static functions. if (base_class->outer != nullptr) { List<GDScriptParser::ClassNode *> script_classes; - get_class_node_current_scope_classes(parser->current_class, &script_classes); + get_class_node_current_scope_classes(base_class->outer, &script_classes); for (GDScriptParser::ClassNode *script_class : script_classes) { if (script_class->has_member(name)) { resolve_class_member(script_class, name, p_identifier); @@ -3393,8 +3413,8 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident } } } else if (ResourceLoader::get_resource_type(autoload.path) == "PackedScene") { - if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(name)) { - Variant constant = GDScriptLanguage::get_singleton()->get_named_globals_map()[name]; + if (GDScriptLanguage::get_singleton()->has_any_global_constant(name)) { + Variant constant = GDScriptLanguage::get_singleton()->get_any_global_constant(name); Node *node = Object::cast_to<Node>(constant); if (node != nullptr) { Ref<GDScript> scr = node->get_script(); @@ -3416,17 +3436,8 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident } } - if (GDScriptLanguage::get_singleton()->get_global_map().has(name)) { - int idx = GDScriptLanguage::get_singleton()->get_global_map()[name]; - Variant constant = GDScriptLanguage::get_singleton()->get_global_array()[idx]; - p_identifier->set_datatype(type_from_variant(constant, p_identifier)); - p_identifier->is_constant = true; - p_identifier->reduced_value = constant; - return; - } - - if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(name)) { - Variant constant = GDScriptLanguage::get_singleton()->get_named_globals_map()[name]; + if (GDScriptLanguage::get_singleton()->has_any_global_constant(name)) { + Variant constant = GDScriptLanguage::get_singleton()->get_any_global_constant(name); p_identifier->set_datatype(type_from_variant(constant, p_identifier)); p_identifier->is_constant = true; p_identifier->reduced_value = constant; @@ -3617,7 +3628,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri result_type = attr_type; p_subscript->is_constant = p_subscript->attribute->is_constant; p_subscript->reduced_value = p_subscript->attribute->reduced_value; - } else if (!base_type.is_constant) { + } else if (!base_type.is_meta_type || !base_type.is_constant) { valid = base_type.kind != GDScriptParser::DataType::BUILTIN; #ifdef DEBUG_ENABLED if (valid) { @@ -3969,10 +3980,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va result.builtin_type = p_value.get_type(); result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; // Constant has explicit type. - if (p_value.get_type() == Variant::NIL) { - // A null value is a variant, not void. - result.kind = GDScriptParser::DataType::VARIANT; - } else if (p_value.get_type() == Variant::OBJECT) { + if (p_value.get_type() == Variant::OBJECT) { // Object is treated as a native type, not a builtin type. result.kind = GDScriptParser::DataType::NATIVE; @@ -3996,37 +4004,27 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va result.kind = GDScriptParser::DataType::CLASS; // This might be an inner class, so we want to get the parser for the root. // But still get the inner class from that tree. - GDScript *current = gds.ptr(); - List<StringName> class_chain; - while (current->_owner) { - // Push to front so it's in reverse. - class_chain.push_front(current->name); - current = current->_owner; - } - - Ref<GDScriptParserRef> ref = get_parser_for(current->get_path()); + String script_path = gds->get_script_path(); + Ref<GDScriptParserRef> ref = get_parser_for(script_path); if (ref.is_null()) { - push_error("Could not find script in path.", p_source); + push_error(vformat(R"(Could not find script "%s".)", script_path), p_source); GDScriptParser::DataType error_type; error_type.kind = GDScriptParser::DataType::VARIANT; return error_type; } - ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED); - - GDScriptParser::ClassNode *found = ref->get_parser()->head; - - for (const StringName &E : class_chain) { - if (!found->has_member(E)) { - return GDScriptParser::DataType(); + Error err = ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED); + GDScriptParser::ClassNode *found = nullptr; + if (err == OK) { + found = ref->get_parser()->find_class(gds->fully_qualified_name); + if (found != nullptr) { + err = resolve_class_inheritance(found, p_source); } - - if (found->get_member(E).type != GDScriptParser::ClassNode::Member::CLASS) { - return GDScriptParser::DataType(); - } - - resolve_class_member(found, E, p_source); - - found = found->get_member(E).m_class; + } + if (err || found == nullptr) { + push_error(vformat(R"(Could not resolve script "%s".)", script_path), p_source); + GDScriptParser::DataType error_type; + error_type.kind = GDScriptParser::DataType::VARIANT; + return error_type; } result.class_type = found; diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index 5972481c3a..6a94c25c88 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -59,7 +59,7 @@ public: type = p_type; } Address(AddressMode p_mode, uint32_t p_address, const GDScriptDataType &p_type = GDScriptDataType()) { - mode = p_mode, + mode = p_mode; address = p_address; type = p_type; } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 4740b9b5a9..cf9e734b05 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -117,8 +117,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D result.builtin_type = p_datatype.builtin_type; result.native_type = p_datatype.native_type; - String root_name = p_datatype.class_type->fqcn.get_slice("::", 0); - bool is_local_class = !root_name.is_empty() && root_name == main_script->fully_qualified_name; + bool is_local_class = parser->has_class(p_datatype.class_type); Ref<GDScript> script; if (is_local_class) { @@ -491,24 +490,29 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } break; case GDScriptParser::Node::CAST: { const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression); - GDScriptParser::DataType og_cast_type = cn->cast_type->get_datatype(); + GDScriptParser::DataType og_cast_type = cn->get_datatype(); GDScriptDataType cast_type = _gdtype_from_datatype(og_cast_type, codegen.script); - if (og_cast_type.kind == GDScriptParser::DataType::ENUM) { - // Enum types are usually treated as dictionaries, but in this case we want to cast to an integer. - cast_type.kind = GDScriptDataType::BUILTIN; - cast_type.builtin_type = Variant::INT; - } + GDScriptCodeGenerator::Address result; + if (cast_type.has_type) { + if (og_cast_type.kind == GDScriptParser::DataType::ENUM) { + // Enum types are usually treated as dictionaries, but in this case we want to cast to an integer. + cast_type.kind = GDScriptDataType::BUILTIN; + cast_type.builtin_type = Variant::INT; + } - // Create temporary for result first since it will be deleted last. - GDScriptCodeGenerator::Address result = codegen.add_temporary(cast_type); + // Create temporary for result first since it will be deleted last. + result = codegen.add_temporary(cast_type); - GDScriptCodeGenerator::Address src = _parse_expression(codegen, r_error, cn->operand); + GDScriptCodeGenerator::Address src = _parse_expression(codegen, r_error, cn->operand); - gen->write_cast(result, src, cast_type); + gen->write_cast(result, src, cast_type); - if (src.mode == GDScriptCodeGenerator::Address::TEMPORARY) { - gen->pop_temporary(); + if (src.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); + } + } else { + result = _parse_expression(codegen, r_error, cn->operand); } return result; @@ -2300,7 +2304,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri return ERR_COMPILATION_FAILED; } - if (base.ptr() == main_script || main_script->is_subclass(base.ptr())) { + if (main_script->has_class(base.ptr())) { Error err = _populate_class_members(base.ptr(), p_class->base_type.class_type, p_keep_state); if (err) { return err; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 79387d1bf6..d84af0c63c 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2848,16 +2848,6 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c break; } - GDScriptParser::CompletionContext c = completion_context; - c.current_function = nullptr; - c.current_suite = nullptr; - c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : nullptr; - if (base.type.kind == GDScriptParser::DataType::CLASS) { - c.current_class = base.type.class_type; - } else { - c.current_class = nullptr; - } - _find_identifiers_in_base(base, false, options, 0); } break; case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: { diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h index 024da1cab7..8b58d7731e 100644 --- a/modules/gdscript/language_server/godot_lsp.h +++ b/modules/gdscript/language_server/godot_lsp.h @@ -702,7 +702,7 @@ struct DiagnosticRelatedInformation { Dictionary to_json() const { Dictionary dict; - dict["location"] = location.to_json(), + dict["location"] = location.to_json(); dict["message"] = message; return dict; } diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd new file mode 100644 index 0000000000..0e1f7256f8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd @@ -0,0 +1,4 @@ +signal your_base +signal my_base +func test(): + your_base = my_base diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out new file mode 100644 index 0000000000..5275183da2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a new value to a constant. diff --git a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd new file mode 100644 index 0000000000..65c0d9dabc --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd @@ -0,0 +1,12 @@ +class A: + class B: + func test(): + print(A.B.D) + +class C: + class D: + pass + +func test(): + var inst = A.B.new() + inst.test() diff --git a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.out b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.out new file mode 100644 index 0000000000..6baed366f6 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot find member "D" in base "B". diff --git a/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd new file mode 100644 index 0000000000..ba1b198cbf --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.gd @@ -0,0 +1,5 @@ +# https://github.com/godotengine/godot/issues/69504#issuecomment-1345725988 + +func test(): + print("cast to Variant == null: ", 1 as Variant == null) + print("cast to Object == null: ", self as Object == null) diff --git a/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out new file mode 100644 index 0000000000..541de99b8e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/cast_non_null.out @@ -0,0 +1,3 @@ +GDTEST_OK +cast to Variant == null: false +cast to Object == null: false diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd new file mode 100644 index 0000000000..757744b6f1 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd @@ -0,0 +1,6 @@ +const External = preload("external_enum_as_constant_external.notest.gd") +const MyEnum = External.MyEnum + +func test(): + print(MyEnum.WAITING == 0) + print(MyEnum.GODOT == 1) diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out new file mode 100644 index 0000000000..9d111a8322 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.out @@ -0,0 +1,3 @@ +GDTEST_OK +true +true diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd new file mode 100644 index 0000000000..7c090844d0 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd @@ -0,0 +1,4 @@ +enum MyEnum { + WAITING, + GODOT +} diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.gd b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.gd new file mode 100644 index 0000000000..18dca109fb --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.gd @@ -0,0 +1,7 @@ +const External = preload("external_inner_class_as_constant_external.notest.gd") +const ExternalInnerClass = External.InnerClass + +func test(): + var inst_external: ExternalInnerClass = ExternalInnerClass.new() + inst_external.x = 4.0 + print(inst_external.x) diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out new file mode 100644 index 0000000000..15666c46ad --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out @@ -0,0 +1,2 @@ +GDTEST_OK +4 diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant_external.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant_external.notest.gd new file mode 100644 index 0000000000..788c99d469 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant_external.notest.gd @@ -0,0 +1,2 @@ +class InnerClass: + var x: = 3.0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd new file mode 100644 index 0000000000..39ced354df --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd @@ -0,0 +1,9 @@ +# https://github.com/godotengine/godot/issues/61159 + +func get_param(): + return null + +func test(): + var v = get_param() + v = get_param() + print(v) diff --git a/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out new file mode 100644 index 0000000000..f0c83a69b3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out @@ -0,0 +1,2 @@ +GDTEST_OK +<null> diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp index fb5fb455b8..27e0052c1a 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.cpp +++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp @@ -36,6 +36,7 @@ #include "core/config/project_settings.h" #include "editor/editor_settings.h" +#include "main/main.h" uint32_t EditorSceneFormatImporterFBX::get_import_flags() const { return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION; @@ -111,4 +112,30 @@ void EditorSceneFormatImporterFBX::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) { } +bool EditorFileSystemImportFormatSupportQueryFBX::is_active() const { + String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path"); + return !FileAccess::exists(fbx2gltf_path); +} + +Vector<String> EditorFileSystemImportFormatSupportQueryFBX::get_file_extensions() const { + Vector<String> ret; + ret.push_back("fbx"); + return ret; +} + +bool EditorFileSystemImportFormatSupportQueryFBX::query() { + FBXImporterManager::get_singleton()->show_dialog(true); + + while (true) { + OS::get_singleton()->delay_usec(1); + DisplayServer::get_singleton()->process_events(); + Main::iteration(); + if (!FBXImporterManager::get_singleton()->is_visible()) { + break; + } + } + + return false; +} + #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_importer_fbx.h b/modules/gltf/editor/editor_scene_importer_fbx.h index 6bf9f3e033..82179cc460 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.h +++ b/modules/gltf/editor/editor_scene_importer_fbx.h @@ -33,6 +33,8 @@ #ifdef TOOLS_ENABLED +#include "editor/editor_file_system.h" +#include "editor/fbx_importer_manager.h" #include "editor/import/resource_importer_scene.h" class Animation; @@ -53,6 +55,15 @@ public: const HashMap<StringName, Variant> &p_options) override; }; +class EditorFileSystemImportFormatSupportQueryFBX : public EditorFileSystemImportFormatSupportQuery { + GDCLASS(EditorFileSystemImportFormatSupportQueryFBX, EditorFileSystemImportFormatSupportQuery); + +public: + virtual bool is_active() const override; + virtual Vector<String> get_file_extensions() const override; + virtual bool query() override; +}; + #endif // TOOLS_ENABLED #endif // EDITOR_SCENE_IMPORTER_FBX_H diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index f4db576b0c..d858f76b28 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -3384,177 +3384,179 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { if (!material->get_name().is_empty()) { d["name"] = _gen_unique_name(p_state, material->get_name()); } + Ref<BaseMaterial3D> base_material = material; - if (base_material.is_valid()) { - Dictionary mr; - { - Array arr; - const Color c = base_material->get_albedo().srgb_to_linear(); - arr.push_back(c.r); - arr.push_back(c.g); - arr.push_back(c.b); - arr.push_back(c.a); - mr["baseColorFactor"] = arr; + if (base_material.is_null()) { + materials.push_back(d); + continue; + } + + Dictionary mr; + { + Array arr; + const Color c = base_material->get_albedo().srgb_to_linear(); + arr.push_back(c.r); + arr.push_back(c.g); + arr.push_back(c.b); + arr.push_back(c.a); + mr["baseColorFactor"] = arr; + } + { + Dictionary bct; + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + GLTFTextureIndex gltf_texture_index = -1; + + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + albedo_texture->set_name(material->get_name() + "_albedo"); + gltf_texture_index = _set_texture(p_state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); } - { - Dictionary bct; - if (base_material.is_valid()) { - Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - GLTFTextureIndex gltf_texture_index = -1; - - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - albedo_texture->set_name(material->get_name() + "_albedo"); - gltf_texture_index = _set_texture(p_state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); - } - if (gltf_texture_index != -1) { - bct["index"] = gltf_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - bct["extensions"] = extensions; - p_state->use_khr_texture_transform = true; - } - mr["baseColorTexture"] = bct; - } + if (gltf_texture_index != -1) { + bct["index"] = gltf_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + bct["extensions"] = extensions; + p_state->use_khr_texture_transform = true; + } + mr["baseColorTexture"] = bct; + } + } + + mr["metallicFactor"] = base_material->get_metallic(); + mr["roughnessFactor"] = base_material->get_roughness(); + bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); + bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); + bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); + if (has_ao || has_roughness || has_metalness) { + Dictionary mrt; + Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); + BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); + Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); + BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); + Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); + BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); + Ref<ImageTexture> orm_texture; + orm_texture.instantiate(); + Ref<Image> orm_image; + orm_image.instantiate(); + int32_t height = 0; + int32_t width = 0; + Ref<Image> ao_image; + if (has_ao) { + height = ao_texture->get_height(); + width = ao_texture->get_width(); + ao_image = ao_texture->get_image(); + Ref<ImageTexture> img_tex = ao_image; + if (img_tex.is_valid()) { + ao_image = img_tex->get_image(); + } + if (ao_image->is_compressed()) { + ao_image->decompress(); + } + } + Ref<Image> roughness_image; + if (has_roughness) { + height = roughness_texture->get_height(); + width = roughness_texture->get_width(); + roughness_image = roughness_texture->get_image(); + Ref<ImageTexture> img_tex = roughness_image; + if (img_tex.is_valid()) { + roughness_image = img_tex->get_image(); + } + if (roughness_image->is_compressed()) { + roughness_image->decompress(); } } - if (base_material.is_valid()) { - mr["metallicFactor"] = base_material->get_metallic(); - mr["roughnessFactor"] = base_material->get_roughness(); - bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); - bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); - bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); - if (has_ao || has_roughness || has_metalness) { - Dictionary mrt; - Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); - BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel(); - Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); - BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel(); - Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); - BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel(); - Ref<ImageTexture> orm_texture; - orm_texture.instantiate(); - Ref<Image> orm_image; - orm_image.instantiate(); - int32_t height = 0; - int32_t width = 0; - Ref<Image> ao_image; + Ref<Image> metallness_image; + if (has_metalness) { + height = metallic_texture->get_height(); + width = metallic_texture->get_width(); + metallness_image = metallic_texture->get_image(); + Ref<ImageTexture> img_tex = metallness_image; + if (img_tex.is_valid()) { + metallness_image = img_tex->get_image(); + } + if (metallness_image->is_compressed()) { + metallness_image->decompress(); + } + } + Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); + if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { + height = albedo_texture->get_height(); + width = albedo_texture->get_width(); + } + orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); + if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { + ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { + roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { + metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); + } + for (int32_t h = 0; h < height; h++) { + for (int32_t w = 0; w < width; w++) { + Color c = Color(1.0f, 1.0f, 1.0f); if (has_ao) { - height = ao_texture->get_height(); - width = ao_texture->get_width(); - ao_image = ao_texture->get_image(); - Ref<ImageTexture> img_tex = ao_image; - if (img_tex.is_valid()) { - ao_image = img_tex->get_image(); - } - if (ao_image->is_compressed()) { - ao_image->decompress(); + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { + c.r = ao_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { + c.r = ao_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { + c.r = ao_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { + c.r = ao_image->get_pixel(w, h).a; } } - Ref<Image> roughness_image; if (has_roughness) { - height = roughness_texture->get_height(); - width = roughness_texture->get_width(); - roughness_image = roughness_texture->get_image(); - Ref<ImageTexture> img_tex = roughness_image; - if (img_tex.is_valid()) { - roughness_image = img_tex->get_image(); - } - if (roughness_image->is_compressed()) { - roughness_image->decompress(); + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { + c.g = roughness_image->get_pixel(w, h).a; } } - Ref<Image> metallness_image; if (has_metalness) { - height = metallic_texture->get_height(); - width = metallic_texture->get_width(); - metallness_image = metallic_texture->get_image(); - Ref<ImageTexture> img_tex = metallness_image; - if (img_tex.is_valid()) { - metallness_image = img_tex->get_image(); - } - if (metallness_image->is_compressed()) { - metallness_image->decompress(); - } - } - Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); - if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { - height = albedo_texture->get_height(); - width = albedo_texture->get_width(); - } - orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8); - if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) { - ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (roughness_image.is_valid() && roughness_image->get_size() != Vector2(width, height)) { - roughness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - if (metallness_image.is_valid() && metallness_image->get_size() != Vector2(width, height)) { - metallness_image->resize(width, height, Image::INTERPOLATE_LANCZOS); - } - for (int32_t h = 0; h < height; h++) { - for (int32_t w = 0; w < width; w++) { - Color c = Color(1.0f, 1.0f, 1.0f); - if (has_ao) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == ao_channel) { - c.r = ao_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == ao_channel) { - c.r = ao_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == ao_channel) { - c.r = ao_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == ao_channel) { - c.r = ao_image->get_pixel(w, h).a; - } - } - if (has_roughness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == roughness_channel) { - c.g = roughness_image->get_pixel(w, h).a; - } - } - if (has_metalness) { - if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).r; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).g; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).b; - } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { - c.b = metallness_image->get_pixel(w, h).a; - } - } - orm_image->set_pixel(w, h, c); - } - } - orm_image->generate_mipmaps(); - orm_texture->set_image(orm_image); - GLTFTextureIndex orm_texture_index = -1; - if (has_ao || has_roughness || has_metalness) { - orm_texture->set_name(material->get_name() + "_orm"); - orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); - } - if (has_ao) { - Dictionary occt; - occt["index"] = orm_texture_index; - d["occlusionTexture"] = occt; - } - if (has_roughness || has_metalness) { - mrt["index"] = orm_texture_index; - Dictionary extensions = _serialize_texture_transform_uv1(material); - if (!extensions.is_empty()) { - mrt["extensions"] = extensions; - p_state->use_khr_texture_transform = true; + if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_RED == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).r; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_GREEN == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).g; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_BLUE == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).b; + } else if (BaseMaterial3D::TextureChannel::TEXTURE_CHANNEL_ALPHA == metalness_channel) { + c.b = metallness_image->get_pixel(w, h).a; } - mr["metallicRoughnessTexture"] = mrt; } + orm_image->set_pixel(w, h, c); } } - d["pbrMetallicRoughness"] = mr; + orm_image->generate_mipmaps(); + orm_texture->set_image(orm_image); + GLTFTextureIndex orm_texture_index = -1; + if (has_ao || has_roughness || has_metalness) { + orm_texture->set_name(material->get_name() + "_orm"); + orm_texture_index = _set_texture(p_state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); + } + if (has_ao) { + Dictionary occt; + occt["index"] = orm_texture_index; + d["occlusionTexture"] = occt; + } + if (has_roughness || has_metalness) { + mrt["index"] = orm_texture_index; + Dictionary extensions = _serialize_texture_transform_uv1(material); + if (!extensions.is_empty()) { + mrt["extensions"] = extensions; + p_state->use_khr_texture_transform = true; + } + mr["metallicRoughnessTexture"] = mrt; + } } + + d["pbrMetallicRoughness"] = mr; if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { Dictionary nt; Ref<ImageTexture> tex; @@ -3607,6 +3609,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { arr.push_back(c.b); d["emissiveFactor"] = arr; } + if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { Dictionary et; Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); @@ -3621,16 +3624,19 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) { d["emissiveTexture"] = et; } } + const bool ds = base_material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; if (ds) { d["doubleSided"] = ds; } + if (base_material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { d["alphaMode"] = "MASK"; d["alphaCutoff"] = base_material->get_alpha_scissor_threshold(); } else if (base_material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { d["alphaMode"] = "BLEND"; } + materials.push_back(d); } if (!materials.size()) { diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index cd7a23fbb2..2322e13ae2 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -80,16 +80,13 @@ static void _editor_init() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "filesystem/import/fbx/fbx2gltf_path", PROPERTY_HINT_GLOBAL_FILE)); if (fbx_enabled) { - Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (fbx2gltf_path.is_empty()) { - WARN_PRINT("FBX file import is enabled in the project settings, but no FBX2glTF path is configured in the editor settings. FBX files will not be imported."); - } else if (!da->file_exists(fbx2gltf_path)) { - WARN_PRINT("FBX file import is enabled, but the FBX2glTF path doesn't point to an accessible file. FBX files will not be imported."); - } else { - Ref<EditorSceneFormatImporterFBX> importer; - importer.instantiate(); - ResourceImporterScene::add_importer(importer); - } + Ref<EditorSceneFormatImporterFBX> importer; + importer.instantiate(); + ResourceImporterScene::get_scene_singleton()->add_importer(importer); + + Ref<EditorFileSystemImportFormatSupportQueryFBX> fbx_import_query; + fbx_import_query.instantiate(); + EditorFileSystem::get_singleton()->add_import_format_support_query(fbx_import_query); } } #endif // TOOLS_ENABLED diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index bd5c938364..e0fc4e2697 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -89,13 +89,6 @@ Returns an array of [Transform3D] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in local space. </description> </method> - <method name="get_navigation_layer_value" qualifiers="const"> - <return type="bool" /> - <param index="0" name="layer_number" type="int" /> - <description> - Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32. - </description> - </method> <method name="get_navigation_map" qualifiers="const"> <return type="RID" /> <description> @@ -179,14 +172,6 @@ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32. </description> </method> - <method name="set_navigation_layer_value"> - <return type="void" /> - <param index="0" name="layer_number" type="int" /> - <param index="1" name="value" type="bool" /> - <description> - Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32. - </description> - </method> <method name="set_navigation_map"> <return type="void" /> <param index="0" name="navigation_map" type="RID" /> @@ -197,7 +182,7 @@ </methods> <members> <member name="bake_navigation" type="bool" setter="set_bake_navigation" getter="is_baking_navigation" default="false"> - If [code]true[/code], this GridMap bakes a navigation region. + If [code]true[/code], this GridMap creates a navigation region for each cell that uses a [member mesh_library] item with a navigation mesh. The created navigation region will use the navigation layers bitmask assigned to the [MeshLibrary]'s item. </member> <member name="cell_center_x" type="bool" setter="set_center_x" getter="get_center_x" default="true"> If [code]true[/code], grid items are centered on the X axis. @@ -226,12 +211,12 @@ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1"> The physics layers this GridMap detects collisions in. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> + <member name="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0"> + The priority used to solve colliding when occurring penetration. The higher the priority is, the lower the penetration into the object will be. This can for example be used to prevent the player from breaking through the boundaries of a level. + </member> <member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library"> The assigned [MeshLibrary]. </member> - <member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1"> - A bitmask determining all navigation layers the GridMap generated navigation regions belong to. These navigation layers can be checked upon when requesting a path with [method NavigationServer3D.map_get_path]. - </member> <member name="physics_material" type="PhysicsMaterial" setter="set_physics_material" getter="get_physics_material"> Overrides the default friction and bounce physics properties for the whole [GridMap]. </member> diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 06ad806afc..e396d77d86 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -74,7 +74,7 @@ bool GridMap::_set(const StringName &p_name, const Variant &p_value) { bm.mesh = meshes[i]; ERR_CONTINUE(!bm.mesh.is_valid()); bm.instance = RS::get_singleton()->instance_create(); - RS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid()); + RS::get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid()); RS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id()); if (is_inside_tree()) { RS::get_singleton()->instance_set_scenario(bm.instance, get_world_3d()->get_scenario()); @@ -138,7 +138,7 @@ void GridMap::_get_property_list(List<PropertyInfo> *p_list) const { void GridMap::set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; - _reset_physic_bodies_collision_filters(); + _update_physics_bodies_collision_properties(); } uint32_t GridMap::get_collision_layer() const { @@ -147,7 +147,7 @@ uint32_t GridMap::get_collision_layer() const { void GridMap::set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; - _reset_physic_bodies_collision_filters(); + _update_physics_bodies_collision_properties(); } uint32_t GridMap::get_collision_mask() const { @@ -184,6 +184,15 @@ void GridMap::set_collision_mask_value(int p_layer_number, bool p_value) { set_collision_mask(mask); } +void GridMap::set_collision_priority(real_t p_priority) { + collision_priority = p_priority; + _update_physics_bodies_collision_properties(); +} + +real_t GridMap::get_collision_priority() const { + return collision_priority; +} + void GridMap::set_physics_material(Ref<PhysicsMaterial> p_material) { physics_material = p_material; _recreate_octant_data(); @@ -230,7 +239,7 @@ void GridMap::set_navigation_map(RID p_navigation_map) { map_override = p_navigation_map; for (const KeyValue<OctantKey, Octant *> &E : octant_map) { Octant &g = *octant_map[E.key]; - for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) { + for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) { if (F.value.region.is_valid()) { NavigationServer3D::get_singleton()->region_set_map(F.value.region, map_override); } @@ -247,33 +256,6 @@ RID GridMap::get_navigation_map() const { return RID(); } -void GridMap::set_navigation_layers(uint32_t p_navigation_layers) { - navigation_layers = p_navigation_layers; - _recreate_octant_data(); -} - -uint32_t GridMap::get_navigation_layers() const { - return navigation_layers; -} - -void GridMap::set_navigation_layer_value(int p_layer_number, bool p_value) { - ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive."); - ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive."); - uint32_t _navigation_layers = get_navigation_layers(); - if (p_value) { - _navigation_layers |= 1 << (p_layer_number - 1); - } else { - _navigation_layers &= ~(1 << (p_layer_number - 1)); - } - set_navigation_layers(_navigation_layers); -} - -bool GridMap::get_navigation_layer_value(int p_layer_number) const { - ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive."); - ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive."); - return get_navigation_layers() & (1 << (p_layer_number - 1)); -} - void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) { if (!mesh_library.is_null()) { mesh_library->unregister_owner(this); @@ -385,6 +367,7 @@ void GridMap::set_cell_item(const Vector3i &p_position, int p_item, int p_rot) { PhysicsServer3D::get_singleton()->body_attach_object_instance_id(g->static_body, get_instance_id()); PhysicsServer3D::get_singleton()->body_set_collision_layer(g->static_body, collision_layer); PhysicsServer3D::get_singleton()->body_set_collision_mask(g->static_body, collision_mask); + PhysicsServer3D::get_singleton()->body_set_collision_priority(g->static_body, collision_priority); if (physics_material.is_valid()) { PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_FRICTION, physics_material->get_friction()); PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material->get_bounce()); @@ -542,13 +525,13 @@ void GridMap::_octant_transform(const OctantKey &p_key) { } // update transform for NavigationServer regions and navigation debugmesh instances - for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) { + for (const KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) { if (bake_navigation) { if (E.value.region.is_valid()) { NavigationServer3D::get_singleton()->region_set_transform(E.value.region, get_global_transform() * E.value.xform); } - if (E.value.navmesh_debug_instance.is_valid()) { - RS::get_singleton()->instance_set_transform(E.value.navmesh_debug_instance, get_global_transform() * E.value.xform); + if (E.value.navigation_mesh_debug_instance.is_valid()) { + RS::get_singleton()->instance_set_transform(E.value.navigation_mesh_debug_instance, get_global_transform() * E.value.xform); } } } @@ -574,13 +557,13 @@ bool GridMap::_octant_update(const OctantKey &p_key) { } //erase navigation - for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) { + for (const KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) { NavigationServer3D::get_singleton()->free(E.value.region); - if (E.value.navmesh_debug_instance.is_valid()) { - RS::get_singleton()->free(E.value.navmesh_debug_instance); + if (E.value.navigation_mesh_debug_instance.is_valid()) { + RS::get_singleton()->free(E.value.navigation_mesh_debug_instance); } } - g.navmesh_ids.clear(); + g.navigation_cell_ids.clear(); //erase multimeshes @@ -648,17 +631,18 @@ bool GridMap::_octant_update(const OctantKey &p_key) { } } - // add the item's navmesh at given xform to GridMap's Navigation ancestor - Ref<NavigationMesh> navmesh = mesh_library->get_item_navmesh(c.item); - if (navmesh.is_valid()) { - Octant::NavMesh nm; - nm.xform = xform * mesh_library->get_item_navmesh_transform(c.item); + // add the item's navigation_mesh at given xform to GridMap's Navigation ancestor + Ref<NavigationMesh> navigation_mesh = mesh_library->get_item_navigation_mesh(c.item); + if (navigation_mesh.is_valid()) { + Octant::NavigationCell nm; + nm.xform = xform * mesh_library->get_item_navigation_mesh_transform(c.item); + nm.navigation_layers = mesh_library->get_item_navigation_layers(c.item); if (bake_navigation) { RID region = NavigationServer3D::get_singleton()->region_create(); NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id()); - NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers); - NavigationServer3D::get_singleton()->region_set_navmesh(region, navmesh); + NavigationServer3D::get_singleton()->region_set_navigation_layers(region, nm.navigation_layers); + NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, navigation_mesh); NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * nm.xform); if (is_inside_tree()) { if (map_override.is_valid()) { @@ -673,19 +657,19 @@ bool GridMap::_octant_update(const OctantKey &p_key) { // add navigation debugmesh visual instances if debug is enabled SceneTree *st = SceneTree::get_singleton(); if (st && st->is_debugging_navigation_hint()) { - if (!nm.navmesh_debug_instance.is_valid()) { - RID navmesh_debug_rid = navmesh->get_debug_mesh()->get_rid(); - nm.navmesh_debug_instance = RS::get_singleton()->instance_create(); - RS::get_singleton()->instance_set_base(nm.navmesh_debug_instance, navmesh_debug_rid); + if (!nm.navigation_mesh_debug_instance.is_valid()) { + RID navigation_mesh_debug_rid = navigation_mesh->get_debug_mesh()->get_rid(); + nm.navigation_mesh_debug_instance = RS::get_singleton()->instance_create(); + RS::get_singleton()->instance_set_base(nm.navigation_mesh_debug_instance, navigation_mesh_debug_rid); } if (is_inside_tree()) { - RS::get_singleton()->instance_set_scenario(nm.navmesh_debug_instance, get_world_3d()->get_scenario()); - RS::get_singleton()->instance_set_transform(nm.navmesh_debug_instance, get_global_transform() * nm.xform); + RS::get_singleton()->instance_set_scenario(nm.navigation_mesh_debug_instance, get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_transform(nm.navigation_mesh_debug_instance, get_global_transform() * nm.xform); } } #endif // DEBUG_ENABLED } - g.navmesh_ids[E] = nm; + g.navigation_cell_ids[E] = nm; } } @@ -751,10 +735,11 @@ bool GridMap::_octant_update(const OctantKey &p_key) { return false; } -void GridMap::_reset_physic_bodies_collision_filters() { +void GridMap::_update_physics_bodies_collision_properties() { for (const KeyValue<OctantKey, Octant *> &E : octant_map) { PhysicsServer3D::get_singleton()->body_set_collision_layer(E.value->static_body, collision_layer); PhysicsServer3D::get_singleton()->body_set_collision_mask(E.value->static_body, collision_mask); + PhysicsServer3D::get_singleton()->body_set_collision_priority(E.value->static_body, collision_priority); } } @@ -775,14 +760,14 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) { } if (bake_navigation && mesh_library.is_valid()) { - for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) { + for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) { if (cell_map.has(F.key) && F.value.region.is_valid() == false) { - Ref<NavigationMesh> nm = mesh_library->get_item_navmesh(cell_map[F.key].item); - if (nm.is_valid()) { + Ref<NavigationMesh> navigation_mesh = mesh_library->get_item_navigation_mesh(cell_map[F.key].item); + if (navigation_mesh.is_valid()) { RID region = NavigationServer3D::get_singleton()->region_create(); NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id()); - NavigationServer3D::get_singleton()->region_set_navigation_layers(region, navigation_layers); - NavigationServer3D::get_singleton()->region_set_navmesh(region, nm); + NavigationServer3D::get_singleton()->region_set_navigation_layers(region, F.value.navigation_layers); + NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, navigation_mesh); NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * F.value.xform); if (map_override.is_valid()) { NavigationServer3D::get_singleton()->region_set_map(region, map_override); @@ -824,14 +809,14 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) { RS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, RID()); } - for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) { + for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) { if (F.value.region.is_valid()) { NavigationServer3D::get_singleton()->free(F.value.region); F.value.region = RID(); } - if (F.value.navmesh_debug_instance.is_valid()) { - RS::get_singleton()->free(F.value.navmesh_debug_instance); - F.value.navmesh_debug_instance = RID(); + if (F.value.navigation_mesh_debug_instance.is_valid()) { + RS::get_singleton()->free(F.value.navigation_mesh_debug_instance); + F.value.navigation_mesh_debug_instance = RID(); } } @@ -862,15 +847,15 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) { PhysicsServer3D::get_singleton()->free(g.static_body); // Erase navigation - for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) { + for (const KeyValue<IndexKey, Octant::NavigationCell> &E : g.navigation_cell_ids) { if (E.value.region.is_valid()) { NavigationServer3D::get_singleton()->free(E.value.region); } - if (E.value.navmesh_debug_instance.is_valid()) { - RS::get_singleton()->free(E.value.navmesh_debug_instance); + if (E.value.navigation_mesh_debug_instance.is_valid()) { + RS::get_singleton()->free(E.value.navigation_mesh_debug_instance); } } - g.navmesh_ids.clear(); + g.navigation_cell_ids.clear(); #ifdef DEBUG_ENABLED if (bake_navigation) { @@ -1047,6 +1032,9 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &GridMap::set_collision_layer_value); ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &GridMap::get_collision_layer_value); + ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &GridMap::set_collision_priority); + ClassDB::bind_method(D_METHOD("get_collision_priority"), &GridMap::get_collision_priority); + ClassDB::bind_method(D_METHOD("set_physics_material", "material"), &GridMap::set_physics_material); ClassDB::bind_method(D_METHOD("get_physics_material"), &GridMap::get_physics_material); @@ -1056,12 +1044,6 @@ void GridMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &GridMap::set_navigation_map); ClassDB::bind_method(D_METHOD("get_navigation_map"), &GridMap::get_navigation_map); - ClassDB::bind_method(D_METHOD("set_navigation_layers", "layers"), &GridMap::set_navigation_layers); - ClassDB::bind_method(D_METHOD("get_navigation_layers"), &GridMap::get_navigation_layers); - - ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &GridMap::set_navigation_layer_value); - ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &GridMap::get_navigation_layer_value); - ClassDB::bind_method(D_METHOD("set_mesh_library", "mesh_library"), &GridMap::set_mesh_library); ClassDB::bind_method(D_METHOD("get_mesh_library"), &GridMap::get_mesh_library); @@ -1118,9 +1100,9 @@ void GridMap::_bind_methods() { ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority"); ADD_GROUP("Navigation", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_navigation"), "set_bake_navigation", "is_baking_navigation"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); BIND_CONSTANT(INVALID_CELL_ITEM); @@ -1281,7 +1263,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe BakedMesh bm; bm.mesh = mesh; bm.instance = RS::get_singleton()->instance_create(); - RS::get_singleton()->get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid()); + RS::get_singleton()->instance_set_base(bm.instance, bm.mesh->get_rid()); RS::get_singleton()->instance_attach_object_instance_id(bm.instance, get_instance_id()); if (is_inside_tree()) { RS::get_singleton()->instance_set_scenario(bm.instance, get_world_3d()->get_scenario()); @@ -1390,7 +1372,7 @@ void GridMap::_update_octant_navigation_debug_edge_connections_mesh(const Octant Vector<Vector3> vertex_array; - for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) { + for (KeyValue<IndexKey, Octant::NavigationCell> &F : g.navigation_cell_ids) { if (cell_map.has(F.key) && F.value.region.is_valid()) { int connections_count = NavigationServer3D::get_singleton()->region_get_connections_count(F.value.region); if (connections_count == 0) { diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 6a53457d25..2a9f34bdda 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -95,10 +95,11 @@ class GridMap : public Node3D { * A GridMap can have multiple Octants. */ struct Octant { - struct NavMesh { + struct NavigationCell { RID region; Transform3D xform; - RID navmesh_debug_instance; + RID navigation_mesh_debug_instance; + uint32_t navigation_layers = 1; }; struct MultimeshInstance { @@ -124,7 +125,7 @@ class GridMap : public Node3D { bool dirty = false; RID static_body; - HashMap<IndexKey, NavMesh> navmesh_ids; + HashMap<IndexKey, NavigationCell> navigation_cell_ids; }; union OctantKey { @@ -150,6 +151,7 @@ class GridMap : public Node3D { uint32_t collision_layer = 1; uint32_t collision_mask = 1; + real_t collision_priority = 1.0; Ref<PhysicsMaterial> physics_material; bool bake_navigation = false; RID map_override; @@ -185,7 +187,7 @@ class GridMap : public Node3D { return Vector3(p_key.x, p_key.y, p_key.z) * cell_size * octant_size; } - void _reset_physic_bodies_collision_filters(); + void _update_physics_bodies_collision_properties(); void _octant_enter_world(const OctantKey &p_key); void _octant_exit_world(const OctantKey &p_key); bool _octant_update(const OctantKey &p_key); @@ -240,6 +242,9 @@ public: void set_collision_mask_value(int p_layer_number, bool p_value); bool get_collision_mask_value(int p_layer_number) const; + void set_collision_priority(real_t p_priority); + real_t get_collision_priority() const; + void set_physics_material(Ref<PhysicsMaterial> p_material); Ref<PhysicsMaterial> get_physics_material() const; @@ -251,12 +256,6 @@ public: void set_navigation_map(RID p_navigation_map); RID get_navigation_map() const; - void set_navigation_layers(uint32_t p_navigation_layers); - uint32_t get_navigation_layers() const; - - void set_navigation_layer_value(int p_layer_number, bool p_value); - bool get_navigation_layer_value(int p_layer_number) const; - void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library); Ref<MeshLibrary> get_mesh_library() const; diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index d0f52488bb..26739bcdea 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -451,7 +451,7 @@ static String variant_type_to_managed_name(const String &p_var_type_name) { } if (p_var_type_name == Variant::get_type_name(Variant::SIGNAL)) { - return "SignalInfo"; + return "Signal"; } Variant::Type var_types[] = { @@ -2292,7 +2292,7 @@ bool CSharpScript::can_instantiate() const { // For tool scripts, this will never fire if the class is not found. That's because we // don't know if it's a tool script if we can't find the class to access the attributes. if (extra_cond && !valid) { - ERR_FAIL_V_MSG(false, "Cannot instance script because the associated class could not be found. Script: '" + get_path() + "'."); + ERR_FAIL_V_MSG(false, "Cannot instance script because the associated class could not be found. Script: '" + get_path() + "'. Make sure the script exists and contains a class definition with a name that matches the filename of the script exactly (it's case-sensitive)."); } return valid && extra_cond; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index d67e57edc2..8852b7ebad 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -295,8 +295,8 @@ namespace Godot.SourceGenerators foreach (var property in properties) { // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload. - // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable. - if (property.IsWriteOnly || property.IsReadOnly) + // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable. + if (property.IsWriteOnly || property.IsReadOnly || property.SetMethod!.IsInitOnly) continue; var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(property.Type, typeCache); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs index 8b2f96036b..f0a6a72281 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs @@ -311,12 +311,12 @@ namespace Godot.SourceGenerators inputExpr, ")"), // We need a special case for generic Godot collections and GodotObjectOrDerived[], because VariantUtils.ConvertTo<T> is slower MarshalType.GodotGenericDictionary => - source.Append(VariantUtils, ".ConvertToDictionaryObject<", + source.Append(VariantUtils, ".ConvertToDictionary<", ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ", ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"), MarshalType.GodotGenericArray => - source.Append(VariantUtils, ".ConvertToArrayObject<", + source.Append(VariantUtils, ".ConvertToArray<", ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"), _ => source.Append(VariantUtils, ".ConvertTo<", diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs index 6c4206a575..b64b843b7c 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -158,7 +158,7 @@ namespace Godot.SourceGenerators // Generate SetGodotClassPropertyValue bool allPropertiesAreReadOnly = godotClassFields.All(fi => fi.FieldSymbol.IsReadOnly) && - godotClassProperties.All(pi => pi.PropertySymbol.IsReadOnly); + godotClassProperties.All(pi => pi.PropertySymbol.IsReadOnly || pi.PropertySymbol.SetMethod!.IsInitOnly); if (!allPropertiesAreReadOnly) { @@ -168,7 +168,7 @@ namespace Godot.SourceGenerators isFirstEntry = true; foreach (var property in godotClassProperties) { - if (property.PropertySymbol.IsReadOnly) + if (property.PropertySymbol.IsReadOnly || property.PropertySymbol.SetMethod!.IsInitOnly) continue; GeneratePropertySetter(property.PropertySymbol.Name, @@ -407,7 +407,7 @@ namespace Godot.SourceGenerators return null; } - if (propertySymbol.SetMethod == null) + if (propertySymbol.SetMethod == null || propertySymbol.SetMethod.IsInitOnly) { // This should never happen, as we filtered ReadOnly properties, but just in case. Common.ReportExportedMemberIsReadOnly(context, propertySymbol); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs index aa9dd9583e..99a4c95e73 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs @@ -138,14 +138,14 @@ namespace Godot.SourceGenerators } // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload. - // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable. + // Ignore properties without a getter, without a setter or with an init-only setter. Godot properties must be both readable and writable. if (property.IsWriteOnly) { Common.ReportExportedMemberIsWriteOnly(context, property); continue; } - if (property.IsReadOnly) + if (property.IsReadOnly || property.SetMethod!.IsInitOnly) { Common.ReportExportedMemberIsReadOnly(context, property); continue; diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 6559cbf75d..6cfdb15627 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -3650,7 +3650,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype = TypeInterface(); itype.name = "Signal"; itype.cname = itype.name; - itype.proxy_name = "SignalInfo"; + itype.proxy_name = "Signal"; itype.cs_type = itype.proxy_name; itype.cs_in_expr = "%0"; itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(in %1);\n"; @@ -3732,7 +3732,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.cs_out = "%5return new %2(%0(%1));"; // For generic Godot collections, Variant.From<T>/As<T> is slower, so we need this special case - itype.cs_variant_to_managed = "VariantUtils.ConvertToArrayObject(%0)"; + itype.cs_variant_to_managed = "VariantUtils.ConvertToArray(%0)"; itype.cs_managed_to_variant = "VariantUtils.CreateFromArray(%0)"; builtin_types.insert(itype.cname, itype); @@ -3759,7 +3759,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.cs_out = "%5return new %2(%0(%1));"; // For generic Godot collections, Variant.From<T>/As<T> is slower, so we need this special case - itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionaryObject(%0)"; + itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionary(%0)"; itype.cs_managed_to_variant = "VariantUtils.CreateFromDictionary(%0)"; builtin_types.insert(itype.cname, itype); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index 130776499b..df306e5244 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -499,7 +499,7 @@ namespace Godot.Collections VariantUtils.CreateFromArray(godotArray); private static Array<T> FromVariantFunc(in godot_variant variant) => - VariantUtils.ConvertToArrayObject<T>(variant); + VariantUtils.ConvertToArray<T>(variant); static unsafe Array() { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index cf25e1f0ae..b5a8742d3d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -366,7 +366,7 @@ namespace Godot.Collections VariantUtils.CreateFromDictionary(godotDictionary); private static Dictionary<TKey, TValue> FromVariantFunc(in godot_variant variant) => - VariantUtils.ConvertToDictionaryObject<TKey, TValue>(variant); + VariantUtils.ConvertToDictionary<TKey, TValue>(variant); static unsafe Dictionary() { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index 6a4717f2c3..f65f926b22 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -436,7 +436,7 @@ namespace Godot.NativeInterop public static Godot.Object ConvertToGodotObject(in godot_variant p_var) => InteropUtils.UnmanagedGetManaged(ConvertToGodotObjectPtr(p_var)); - public static string ConvertToStringObject(in godot_variant p_var) + public static string ConvertToString(in godot_variant p_var) { switch (p_var.Type) { @@ -455,65 +455,65 @@ namespace Godot.NativeInterop } } - public static godot_string_name ConvertToStringName(in godot_variant p_var) + public static godot_string_name ConvertToNativeStringName(in godot_variant p_var) => p_var.Type == Variant.Type.StringName ? NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName) : NativeFuncs.godotsharp_variant_as_string_name(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static StringName ConvertToStringNameObject(in godot_variant p_var) - => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToStringName(p_var)); + public static StringName ConvertToStringName(in godot_variant p_var) + => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToNativeStringName(p_var)); - public static godot_node_path ConvertToNodePath(in godot_variant p_var) + public static godot_node_path ConvertToNativeNodePath(in godot_variant p_var) => p_var.Type == Variant.Type.NodePath ? NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath) : NativeFuncs.godotsharp_variant_as_node_path(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static NodePath ConvertToNodePathObject(in godot_variant p_var) - => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNodePath(p_var)); + public static NodePath ConvertToNodePath(in godot_variant p_var) + => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNativeNodePath(p_var)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_callable ConvertToCallable(in godot_variant p_var) + public static godot_callable ConvertToNativeCallable(in godot_variant p_var) => NativeFuncs.godotsharp_variant_as_callable(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Callable ConvertToCallableManaged(in godot_variant p_var) - => Marshaling.ConvertCallableToManaged(ConvertToCallable(p_var)); + public static Callable ConvertToCallable(in godot_variant p_var) + => Marshaling.ConvertCallableToManaged(ConvertToNativeCallable(p_var)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_signal ConvertToSignal(in godot_variant p_var) + public static godot_signal ConvertToNativeSignal(in godot_variant p_var) => NativeFuncs.godotsharp_variant_as_signal(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Signal ConvertToSignalManaged(in godot_variant p_var) - => Marshaling.ConvertSignalToManaged(ConvertToSignal(p_var)); + public static Signal ConvertToSignal(in godot_variant p_var) + => Marshaling.ConvertSignalToManaged(ConvertToNativeSignal(p_var)); - public static godot_array ConvertToArray(in godot_variant p_var) + public static godot_array ConvertToNativeArray(in godot_variant p_var) => p_var.Type == Variant.Type.Array ? NativeFuncs.godotsharp_array_new_copy(p_var.Array) : NativeFuncs.godotsharp_variant_as_array(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Collections.Array ConvertToArrayObject(in godot_variant p_var) - => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var)); + public static Collections.Array ConvertToArray(in godot_variant p_var) + => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToNativeArray(p_var)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Array<T> ConvertToArrayObject<T>(in godot_variant p_var) - => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var)); + public static Array<T> ConvertToArray<T>(in godot_variant p_var) + => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToNativeArray(p_var)); - public static godot_dictionary ConvertToDictionary(in godot_variant p_var) + public static godot_dictionary ConvertToNativeDictionary(in godot_variant p_var) => p_var.Type == Variant.Type.Dictionary ? NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) : NativeFuncs.godotsharp_variant_as_dictionary(p_var); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Dictionary ConvertToDictionaryObject(in godot_variant p_var) - => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var)); + public static Dictionary ConvertToDictionary(in godot_variant p_var) + => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToNativeDictionary(p_var)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Dictionary<TKey, TValue> ConvertToDictionaryObject<TKey, TValue>(in godot_variant p_var) - => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var)); + public static Dictionary<TKey, TValue> ConvertToDictionary<TKey, TValue>(in godot_variant p_var) + => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToNativeDictionary(p_var)); public static byte[] ConvertAsPackedByteArrayToSystemArray(in godot_variant p_var) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs index ebfc713ee4..3d64533269 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs @@ -315,13 +315,13 @@ public partial class VariantUtils return UnsafeAsT(ConvertToPlane(variant)); if (typeof(T) == typeof(Callable)) - return UnsafeAsT(ConvertToCallableManaged(variant)); + return UnsafeAsT(ConvertToCallable(variant)); if (typeof(T) == typeof(Signal)) - return UnsafeAsT(ConvertToSignalManaged(variant)); + return UnsafeAsT(ConvertToSignal(variant)); if (typeof(T) == typeof(string)) - return UnsafeAsT(ConvertToStringObject(variant)); + return UnsafeAsT(ConvertToString(variant)); if (typeof(T) == typeof(byte[])) return UnsafeAsT(ConvertAsPackedByteArrayToSystemArray(variant)); @@ -360,19 +360,19 @@ public partial class VariantUtils return UnsafeAsT(ConvertToSystemArrayOfRID(variant)); if (typeof(T) == typeof(StringName)) - return UnsafeAsT(ConvertToStringNameObject(variant)); + return UnsafeAsT(ConvertToStringName(variant)); if (typeof(T) == typeof(NodePath)) - return UnsafeAsT(ConvertToNodePathObject(variant)); + return UnsafeAsT(ConvertToNodePath(variant)); if (typeof(T) == typeof(RID)) return UnsafeAsT(ConvertToRID(variant)); if (typeof(T) == typeof(Godot.Collections.Dictionary)) - return UnsafeAsT(ConvertToDictionaryObject(variant)); + return UnsafeAsT(ConvertToDictionary(variant)); if (typeof(T) == typeof(Godot.Collections.Array)) - return UnsafeAsT(ConvertToArrayObject(variant)); + return UnsafeAsT(ConvertToArray(variant)); if (typeof(T) == typeof(Variant)) return UnsafeAsT(Variant.CreateCopyingBorrowed(variant)); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs index c4c53a39f9..da12309217 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs @@ -212,7 +212,7 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public string AsString() => - VariantUtils.ConvertToStringObject((godot_variant)NativeVar); + VariantUtils.ConvertToString((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector2 AsVector2() => @@ -280,11 +280,11 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public Callable AsCallable() => - VariantUtils.ConvertToCallableManaged((godot_variant)NativeVar); + VariantUtils.ConvertToCallable((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Signal AsSignal() => - VariantUtils.ConvertToSignalManaged((godot_variant)NativeVar); + VariantUtils.ConvertToSignal((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte[] AsByteArray() => @@ -329,11 +329,11 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public Collections.Dictionary<TKey, TValue> AsGodotDictionary<TKey, TValue>() => - VariantUtils.ConvertToDictionaryObject<TKey, TValue>((godot_variant)NativeVar); + VariantUtils.ConvertToDictionary<TKey, TValue>((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Collections.Array<T> AsGodotArray<T>() => - VariantUtils.ConvertToArrayObject<T>((godot_variant)NativeVar); + VariantUtils.ConvertToArray<T>((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public StringName[] AsSystemArrayOfStringName() => @@ -353,11 +353,11 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public StringName AsStringName() => - VariantUtils.ConvertToStringNameObject((godot_variant)NativeVar); + VariantUtils.ConvertToStringName((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public NodePath AsNodePath() => - VariantUtils.ConvertToNodePathObject((godot_variant)NativeVar); + VariantUtils.ConvertToNodePath((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public RID AsRID() => @@ -365,11 +365,11 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public Collections.Dictionary AsGodotDictionary() => - VariantUtils.ConvertToDictionaryObject((godot_variant)NativeVar); + VariantUtils.ConvertToDictionary((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Collections.Array AsGodotArray() => - VariantUtils.ConvertToArrayObject((godot_variant)NativeVar); + VariantUtils.ConvertToArray((godot_variant)NativeVar); // Explicit conversion operators to supported types diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index e5949c935b..58a0982425 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -36,6 +36,8 @@ #include "navigation_mesh_generator.h" #endif +using namespace NavigationUtilities; + /// Creates a struct for each function and a function that once called creates /// an instance of that struct with the submitted parameters. /// Then, that struct is stored in an array; the `sync` function consume that array. @@ -228,7 +230,7 @@ Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin, const NavMap *map = map_owner.get_or_null(p_map); ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>()); - return map->get_path(p_origin, p_destination, p_optimize, p_navigation_layers); + return map->get_path(p_origin, p_destination, p_optimize, p_navigation_layers, nullptr, nullptr, nullptr); } Vector3 GodotNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const { @@ -421,20 +423,20 @@ uint32_t GodotNavigationServer::region_get_navigation_layers(RID p_region) const return region->get_navigation_layers(); } -COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh) { +COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref<NavigationMesh>, p_navigation_mesh) { NavRegion *region = region_owner.get_or_null(p_region); ERR_FAIL_COND(region == nullptr); - region->set_mesh(p_nav_mesh); + region->set_mesh(p_navigation_mesh); } -void GodotNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const { - ERR_FAIL_COND(r_mesh.is_null()); - ERR_FAIL_COND(p_node == nullptr); +void GodotNavigationServer::region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) const { + ERR_FAIL_COND(p_navigation_mesh.is_null()); + ERR_FAIL_COND(p_root_node == nullptr); #ifndef _3D_DISABLED - NavigationMeshGenerator::get_singleton()->clear(r_mesh); - NavigationMeshGenerator::get_singleton()->bake(r_mesh, p_node); + NavigationMeshGenerator::get_singleton()->clear(p_navigation_mesh); + NavigationMeshGenerator::get_singleton()->bake(p_navigation_mesh, p_root_node); #endif } @@ -838,20 +840,34 @@ void GodotNavigationServer::process(real_t p_delta_time) { } } -NavigationUtilities::PathQueryResult GodotNavigationServer::_query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const { - NavigationUtilities::PathQueryResult r_query_result; +PathQueryResult GodotNavigationServer::_query_path(const PathQueryParameters &p_parameters) const { + PathQueryResult r_query_result; const NavMap *map = map_owner.get_or_null(p_parameters.map); ERR_FAIL_COND_V(map == nullptr, r_query_result); // run the pathfinding - if (p_parameters.pathfinding_algorithm == NavigationUtilities::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR) { + if (p_parameters.pathfinding_algorithm == PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR) { // while postprocessing is still part of map.get_path() need to check and route it here for the correct "optimize" post-processing - if (p_parameters.path_postprocessing == NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL) { - r_query_result.path = map->get_path(p_parameters.start_position, p_parameters.target_position, true, p_parameters.navigation_layers); - } else if (p_parameters.path_postprocessing == NavigationUtilities::PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED) { - r_query_result.path = map->get_path(p_parameters.start_position, p_parameters.target_position, false, p_parameters.navigation_layers); + if (p_parameters.path_postprocessing == PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL) { + r_query_result.path = map->get_path( + p_parameters.start_position, + p_parameters.target_position, + true, + p_parameters.navigation_layers, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES) ? &r_query_result.path_types : nullptr, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS) ? &r_query_result.path_rids : nullptr, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS) ? &r_query_result.path_owner_ids : nullptr); + } else if (p_parameters.path_postprocessing == PathPostProcessing::PATH_POSTPROCESSING_EDGECENTERED) { + r_query_result.path = map->get_path( + p_parameters.start_position, + p_parameters.target_position, + false, + p_parameters.navigation_layers, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_TYPES) ? &r_query_result.path_types : nullptr, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_RIDS) ? &r_query_result.path_rids : nullptr, + p_parameters.metadata_flags.has_flag(PathMetadataFlags::PATH_INCLUDE_OWNERS) ? &r_query_result.path_owner_ids : nullptr); } } else { return r_query_result; diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index 18431e39b8..6f39420c67 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -135,8 +135,8 @@ public: COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers); virtual uint32_t region_get_navigation_layers(RID p_region) const override; COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform); - COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh); - virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const override; + COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref<NavigationMesh>, p_navigation_mesh); + virtual void region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) const override; virtual int region_get_connections_count(RID p_region) const override; virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override; virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override; diff --git a/modules/navigation/nav_base.h b/modules/navigation/nav_base.h index f5d2880d36..a3ab77301b 100644 --- a/modules/navigation/nav_base.h +++ b/modules/navigation/nav_base.h @@ -33,6 +33,7 @@ #include "nav_rid.h" #include "nav_utils.h" +#include "servers/navigation/navigation_utilities.h" class NavMap; @@ -42,8 +43,11 @@ protected: float enter_cost = 0.0; float travel_cost = 1.0; ObjectID owner_id; + NavigationUtilities::PathSegmentType type; public: + NavigationUtilities::PathSegmentType get_type() const { return type; } + void set_navigation_layers(uint32_t p_navigation_layers) { navigation_layers = p_navigation_layers; } uint32_t get_navigation_layers() const { return navigation_layers; } diff --git a/modules/navigation/nav_link.h b/modules/navigation/nav_link.h index 8f51a63951..e9c69286f9 100644 --- a/modules/navigation/nav_link.h +++ b/modules/navigation/nav_link.h @@ -43,6 +43,10 @@ class NavLink : public NavBase { bool link_dirty = true; public: + NavLink() { + type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_LINK; + } + void set_map(NavMap *p_map); NavMap *get_map() const { return map; diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 83862e1e34..8d58c9335d 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -38,6 +38,18 @@ #define THREE_POINTS_CROSS_PRODUCT(m_a, m_b, m_c) (((m_c) - (m_a)).cross((m_b) - (m_a))) +// Helper macro +#define APPEND_METADATA(poly) \ + if (r_path_types) { \ + r_path_types->push_back(poly->owner->get_type()); \ + } \ + if (r_path_rids) { \ + r_path_rids->push_back(poly->owner->get_self()); \ + } \ + if (r_path_owners) { \ + r_path_owners->push_back(poly->owner->get_owner_id()); \ + } + void NavMap::set_up(Vector3 p_up) { up = p_up; regenerate_polygons = true; @@ -71,7 +83,18 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const { return p; } -Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) const { +Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const { + // Clear metadata outputs. + if (r_path_types) { + r_path_types->clear(); + } + if (r_path_rids) { + r_path_rids->clear(); + } + if (r_path_owners) { + r_path_owners->clear(); + } + // Find the start poly and the end poly on this map. const gd::Polygon *begin_poly = nullptr; const gd::Polygon *end_poly = nullptr; @@ -115,6 +138,24 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p return Vector<Vector3>(); } if (begin_poly == end_poly) { + if (r_path_types) { + r_path_types->resize(2); + r_path_types->write[0] = begin_poly->owner->get_type(); + r_path_types->write[1] = end_poly->owner->get_type(); + } + + if (r_path_rids) { + r_path_rids->resize(2); + (*r_path_rids)[0] = begin_poly->owner->get_self(); + (*r_path_rids)[1] = end_poly->owner->get_self(); + } + + if (r_path_owners) { + r_path_owners->resize(2); + r_path_owners->write[0] = begin_poly->owner->get_owner_id(); + r_path_owners->write[1] = end_poly->owner->get_owner_id(); + } + Vector<Vector3> path; path.resize(2); path.write[0] = begin_point; @@ -296,6 +337,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p gd::NavigationPoly *p = apex_poly; path.push_back(end_point); + APPEND_METADATA(end_poly); while (p) { // Set left and right points of the pathway between polygons. @@ -312,7 +354,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p left_poly = p; left_portal = left; } else { - clip_path(navigation_polys, path, apex_poly, right_portal, right_poly); + clip_path(navigation_polys, path, apex_poly, right_portal, right_poly, r_path_types, r_path_rids, r_path_owners); apex_point = right_portal; p = right_poly; @@ -320,7 +362,9 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p apex_poly = p; left_portal = apex_point; right_portal = apex_point; + path.push_back(apex_point); + APPEND_METADATA(apex_poly->poly); skip = true; } } @@ -331,7 +375,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p right_poly = p; right_portal = right; } else { - clip_path(navigation_polys, path, apex_poly, left_portal, left_poly); + clip_path(navigation_polys, path, apex_poly, left_portal, left_poly, r_path_types, r_path_rids, r_path_owners); apex_point = left_portal; p = left_poly; @@ -339,7 +383,9 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p apex_poly = p; right_portal = apex_point; left_portal = apex_point; + path.push_back(apex_point); + APPEND_METADATA(apex_poly->poly); } } @@ -355,12 +401,23 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p // If the last point is not the begin point, add it to the list. if (path[path.size() - 1] != begin_point) { path.push_back(begin_point); + APPEND_METADATA(begin_poly); } path.reverse(); + if (r_path_types) { + r_path_types->reverse(); + } + if (r_path_rids) { + r_path_rids->reverse(); + } + if (r_path_owners) { + r_path_owners->reverse(); + } } else { path.push_back(end_point); + APPEND_METADATA(end_poly); // Add mid points int np_id = least_cost_id; @@ -369,18 +426,37 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p int prev = navigation_polys[np_id].back_navigation_edge; int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size(); Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5; + path.push_back(point); + APPEND_METADATA(navigation_polys[np_id].poly); } else { path.push_back(navigation_polys[np_id].entry); + APPEND_METADATA(navigation_polys[np_id].poly); } np_id = navigation_polys[np_id].back_navigation_poly_id; } path.push_back(begin_point); + APPEND_METADATA(begin_poly); + path.reverse(); + if (r_path_types) { + r_path_types->reverse(); + } + if (r_path_rids) { + r_path_rids->reverse(); + } + if (r_path_owners) { + r_path_owners->reverse(); + } } + // Ensure post conditions (path arrays MUST match in size). + CRASH_COND(r_path_types && path.size() != r_path_types->size()); + CRASH_COND(r_path_rids && path.size() != r_path_rids->size()); + CRASH_COND(r_path_owners && path.size() != r_path_owners->size()); + return path; } @@ -837,7 +913,7 @@ void NavMap::dispatch_callbacks() { } } -void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly) const { +void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const { Vector3 from = path[path.size() - 1]; if (from.is_equal_approx(p_to_point)) { @@ -863,6 +939,7 @@ void NavMap::clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys if (cut_plane.intersects_segment(pathway_start, pathway_end, &inters)) { if (!inters.is_equal_approx(p_to_point) && !inters.is_equal_approx(path[path.size() - 1])) { path.push_back(inters); + APPEND_METADATA(from_poly->poly); } } } diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index a3da9fa727..3be13133d2 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -115,7 +115,7 @@ public: gd::PointKey get_point_key(const Vector3 &p_pos) const; - Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const; + Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const; Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const; Vector3 get_closest_point(const Vector3 &p_point) const; Vector3 get_closest_point_normal(const Vector3 &p_point) const; @@ -154,7 +154,7 @@ public: private: void compute_single_step(uint32_t index, RvoAgent **agent); - void clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly) const; + void clip_path(const LocalVector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly, Vector<int32_t> *r_path_types, TypedArray<RID> *r_path_rids, Vector<int64_t> *r_path_owners) const; }; #endif // NAV_MAP_H diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h index 8d2b5aa9eb..3ef3ef5748 100644 --- a/modules/navigation/nav_region.h +++ b/modules/navigation/nav_region.h @@ -48,7 +48,9 @@ class NavRegion : public NavBase { LocalVector<gd::Polygon> polygons; public: - NavRegion() {} + NavRegion() { + type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_REGION; + } void scratch_polygons() { polygons_dirty = true; diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index f0d3e329ce..62db6ff4e9 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -470,14 +470,14 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans } } -void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh) { +void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_navigation_mesh) { Vector<Vector3> nav_vertices; for (int i = 0; i < p_detail_mesh->nverts; i++) { const float *v = &p_detail_mesh->verts[i * 3]; nav_vertices.push_back(Vector3(v[0], v[1], v[2])); } - p_nav_mesh->set_vertices(nav_vertices); + p_navigation_mesh->set_vertices(nav_vertices); for (int i = 0; i < p_detail_mesh->nmeshes; i++) { const unsigned int *m = &p_detail_mesh->meshes[i * 4]; @@ -492,13 +492,13 @@ void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(con nav_indices.write[0] = ((int)(bverts + tris[j * 4 + 0])); nav_indices.write[1] = ((int)(bverts + tris[j * 4 + 2])); nav_indices.write[2] = ((int)(bverts + tris[j * 4 + 1])); - p_nav_mesh->add_polygon(nav_indices); + p_navigation_mesh->add_polygon(nav_indices); } } } void NavigationMeshGenerator::_build_recast_navigation_mesh( - Ref<NavigationMesh> p_nav_mesh, + Ref<NavigationMesh> p_navigation_mesh, #ifdef TOOLS_ENABLED EditorProgress *ep, #endif @@ -528,42 +528,42 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh( rcConfig cfg; memset(&cfg, 0, sizeof(cfg)); - cfg.cs = p_nav_mesh->get_cell_size(); - cfg.ch = p_nav_mesh->get_cell_height(); - cfg.walkableSlopeAngle = p_nav_mesh->get_agent_max_slope(); - cfg.walkableHeight = (int)Math::ceil(p_nav_mesh->get_agent_height() / cfg.ch); - cfg.walkableClimb = (int)Math::floor(p_nav_mesh->get_agent_max_climb() / cfg.ch); - cfg.walkableRadius = (int)Math::ceil(p_nav_mesh->get_agent_radius() / cfg.cs); - cfg.maxEdgeLen = (int)(p_nav_mesh->get_edge_max_length() / p_nav_mesh->get_cell_size()); - cfg.maxSimplificationError = p_nav_mesh->get_edge_max_error(); - cfg.minRegionArea = (int)(p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size()); - cfg.mergeRegionArea = (int)(p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size()); - cfg.maxVertsPerPoly = (int)p_nav_mesh->get_verts_per_poly(); - cfg.detailSampleDist = MAX(p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance(), 0.1f); - cfg.detailSampleMaxError = p_nav_mesh->get_cell_height() * p_nav_mesh->get_detail_sample_max_error(); - - if (!Math::is_equal_approx((float)cfg.walkableHeight * cfg.ch, p_nav_mesh->get_agent_height())) { + cfg.cs = p_navigation_mesh->get_cell_size(); + cfg.ch = p_navigation_mesh->get_cell_height(); + cfg.walkableSlopeAngle = p_navigation_mesh->get_agent_max_slope(); + cfg.walkableHeight = (int)Math::ceil(p_navigation_mesh->get_agent_height() / cfg.ch); + cfg.walkableClimb = (int)Math::floor(p_navigation_mesh->get_agent_max_climb() / cfg.ch); + cfg.walkableRadius = (int)Math::ceil(p_navigation_mesh->get_agent_radius() / cfg.cs); + cfg.maxEdgeLen = (int)(p_navigation_mesh->get_edge_max_length() / p_navigation_mesh->get_cell_size()); + cfg.maxSimplificationError = p_navigation_mesh->get_edge_max_error(); + cfg.minRegionArea = (int)(p_navigation_mesh->get_region_min_size() * p_navigation_mesh->get_region_min_size()); + cfg.mergeRegionArea = (int)(p_navigation_mesh->get_region_merge_size() * p_navigation_mesh->get_region_merge_size()); + cfg.maxVertsPerPoly = (int)p_navigation_mesh->get_vertices_per_polygon(); + cfg.detailSampleDist = MAX(p_navigation_mesh->get_cell_size() * p_navigation_mesh->get_detail_sample_distance(), 0.1f); + cfg.detailSampleMaxError = p_navigation_mesh->get_cell_height() * p_navigation_mesh->get_detail_sample_max_error(); + + if (!Math::is_equal_approx((float)cfg.walkableHeight * cfg.ch, p_navigation_mesh->get_agent_height())) { WARN_PRINT("Property agent_height is ceiled to cell_height voxel units and loses precision."); } - if (!Math::is_equal_approx((float)cfg.walkableClimb * cfg.ch, p_nav_mesh->get_agent_max_climb())) { + if (!Math::is_equal_approx((float)cfg.walkableClimb * cfg.ch, p_navigation_mesh->get_agent_max_climb())) { WARN_PRINT("Property agent_max_climb is floored to cell_height voxel units and loses precision."); } - if (!Math::is_equal_approx((float)cfg.walkableRadius * cfg.cs, p_nav_mesh->get_agent_radius())) { + if (!Math::is_equal_approx((float)cfg.walkableRadius * cfg.cs, p_navigation_mesh->get_agent_radius())) { WARN_PRINT("Property agent_radius is ceiled to cell_size voxel units and loses precision."); } - if (!Math::is_equal_approx((float)cfg.maxEdgeLen * cfg.cs, p_nav_mesh->get_edge_max_length())) { + if (!Math::is_equal_approx((float)cfg.maxEdgeLen * cfg.cs, p_navigation_mesh->get_edge_max_length())) { WARN_PRINT("Property edge_max_length is rounded to cell_size voxel units and loses precision."); } - if (!Math::is_equal_approx((float)cfg.minRegionArea, p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size())) { + if (!Math::is_equal_approx((float)cfg.minRegionArea, p_navigation_mesh->get_region_min_size() * p_navigation_mesh->get_region_min_size())) { WARN_PRINT("Property region_min_size is converted to int and loses precision."); } - if (!Math::is_equal_approx((float)cfg.mergeRegionArea, p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size())) { + if (!Math::is_equal_approx((float)cfg.mergeRegionArea, p_navigation_mesh->get_region_merge_size() * p_navigation_mesh->get_region_merge_size())) { WARN_PRINT("Property region_merge_size is converted to int and loses precision."); } - if (!Math::is_equal_approx((float)cfg.maxVertsPerPoly, p_nav_mesh->get_verts_per_poly())) { - WARN_PRINT("Property verts_per_poly is converted to int and loses precision."); + if (!Math::is_equal_approx((float)cfg.maxVertsPerPoly, p_navigation_mesh->get_vertices_per_polygon())) { + WARN_PRINT("Property vertices_per_polygon is converted to int and loses precision."); } - if (p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance() < 0.1f) { + if (p_navigation_mesh->get_cell_size() * p_navigation_mesh->get_detail_sample_distance() < 0.1f) { WARN_PRINT("Property detail_sample_distance is clamped to 0.1 world units as the resulting value from multiplying with cell_size is too low."); } @@ -574,9 +574,9 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh( cfg.bmax[1] = bmax[1]; cfg.bmax[2] = bmax[2]; - AABB baking_aabb = p_nav_mesh->get_filter_baking_aabb(); + AABB baking_aabb = p_navigation_mesh->get_filter_baking_aabb(); if (baking_aabb.has_volume()) { - Vector3 baking_aabb_offset = p_nav_mesh->get_filter_baking_aabb_offset(); + Vector3 baking_aabb_offset = p_navigation_mesh->get_filter_baking_aabb_offset(); cfg.bmin[0] = baking_aabb.position[0] + baking_aabb_offset.x; cfg.bmin[1] = baking_aabb.position[1] + baking_aabb_offset.y; cfg.bmin[2] = baking_aabb.position[2] + baking_aabb_offset.z; @@ -627,13 +627,13 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh( ERR_FAIL_COND(!rcRasterizeTriangles(&ctx, verts, nverts, tris, tri_areas.ptr(), ntris, *hf, cfg.walkableClimb)); } - if (p_nav_mesh->get_filter_low_hanging_obstacles()) { + if (p_navigation_mesh->get_filter_low_hanging_obstacles()) { rcFilterLowHangingWalkableObstacles(&ctx, cfg.walkableClimb, *hf); } - if (p_nav_mesh->get_filter_ledge_spans()) { + if (p_navigation_mesh->get_filter_ledge_spans()) { rcFilterLedgeSpans(&ctx, cfg.walkableHeight, cfg.walkableClimb, *hf); } - if (p_nav_mesh->get_filter_walkable_low_height_spans()) { + if (p_navigation_mesh->get_filter_walkable_low_height_spans()) { rcFilterWalkableLowHeightSpans(&ctx, cfg.walkableHeight, *hf); } @@ -665,10 +665,10 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh( } #endif - if (p_nav_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_WATERSHED) { + if (p_navigation_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_WATERSHED) { ERR_FAIL_COND(!rcBuildDistanceField(&ctx, *chf)); ERR_FAIL_COND(!rcBuildRegions(&ctx, *chf, 0, cfg.minRegionArea, cfg.mergeRegionArea)); - } else if (p_nav_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_MONOTONE) { + } else if (p_navigation_mesh->get_sample_partition_type() == NavigationMesh::SAMPLE_PARTITION_MONOTONE) { ERR_FAIL_COND(!rcBuildRegionsMonotone(&ctx, *chf, 0, cfg.minRegionArea, cfg.mergeRegionArea)); } else { ERR_FAIL_COND(!rcBuildLayerRegions(&ctx, *chf, 0, cfg.minRegionArea)); @@ -710,7 +710,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh( } #endif - _convert_detail_mesh_to_native_navigation_mesh(detail_mesh, p_nav_mesh); + _convert_detail_mesh_to_native_navigation_mesh(detail_mesh, p_navigation_mesh); rcFreePolyMesh(poly_mesh); poly_mesh = nullptr; @@ -729,8 +729,8 @@ NavigationMeshGenerator::NavigationMeshGenerator() { NavigationMeshGenerator::~NavigationMeshGenerator() { } -void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) { - ERR_FAIL_COND_MSG(!p_nav_mesh.is_valid(), "Invalid navigation mesh."); +void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) { + ERR_FAIL_COND_MSG(!p_navigation_mesh.is_valid(), "Invalid navigation mesh."); #ifdef TOOLS_ENABLED EditorProgress *ep(nullptr); @@ -755,17 +755,17 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) List<Node *> parse_nodes; - if (p_nav_mesh->get_source_geometry_mode() == NavigationMesh::SOURCE_GEOMETRY_NAVMESH_CHILDREN) { - parse_nodes.push_back(p_node); + if (p_navigation_mesh->get_source_geometry_mode() == NavigationMesh::SOURCE_GEOMETRY_ROOT_NODE_CHILDREN) { + parse_nodes.push_back(p_root_node); } else { - p_node->get_tree()->get_nodes_in_group(p_nav_mesh->get_source_group_name(), &parse_nodes); + p_root_node->get_tree()->get_nodes_in_group(p_navigation_mesh->get_source_group_name(), &parse_nodes); } - Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_global_transform().affine_inverse(); + Transform3D navmesh_xform = Object::cast_to<Node3D>(p_root_node)->get_global_transform().affine_inverse(); for (Node *E : parse_nodes) { - NavigationMesh::ParsedGeometryType geometry_type = p_nav_mesh->get_parsed_geometry_type(); - uint32_t collision_mask = p_nav_mesh->get_collision_mask(); - bool recurse_children = p_nav_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT; + NavigationMesh::ParsedGeometryType geometry_type = p_navigation_mesh->get_parsed_geometry_type(); + uint32_t collision_mask = p_navigation_mesh->get_collision_mask(); + bool recurse_children = p_navigation_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT; _parse_geometry(navmesh_xform, E, vertices, indices, geometry_type, collision_mask, recurse_children); } @@ -777,7 +777,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) rcPolyMeshDetail *detail_mesh = nullptr; _build_recast_navigation_mesh( - p_nav_mesh, + p_navigation_mesh, #ifdef TOOLS_ENABLED ep, #endif @@ -816,16 +816,16 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) #endif } -void NavigationMeshGenerator::clear(Ref<NavigationMesh> p_nav_mesh) { - if (p_nav_mesh.is_valid()) { - p_nav_mesh->clear_polygons(); - p_nav_mesh->set_vertices(Vector<Vector3>()); +void NavigationMeshGenerator::clear(Ref<NavigationMesh> p_navigation_mesh) { + if (p_navigation_mesh.is_valid()) { + p_navigation_mesh->clear_polygons(); + p_navigation_mesh->set_vertices(Vector<Vector3>()); } } void NavigationMeshGenerator::_bind_methods() { - ClassDB::bind_method(D_METHOD("bake", "nav_mesh", "root_node"), &NavigationMeshGenerator::bake); - ClassDB::bind_method(D_METHOD("clear", "nav_mesh"), &NavigationMeshGenerator::clear); + ClassDB::bind_method(D_METHOD("bake", "navigation_mesh", "root_node"), &NavigationMeshGenerator::bake); + ClassDB::bind_method(D_METHOD("clear", "navigation_mesh"), &NavigationMeshGenerator::clear); } #endif diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h index 8cc1531b53..f6bf39d714 100644 --- a/modules/navigation/navigation_mesh_generator.h +++ b/modules/navigation/navigation_mesh_generator.h @@ -55,9 +55,9 @@ protected: static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); static void _parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); - static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh); + static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_navigation_mesh); static void _build_recast_navigation_mesh( - Ref<NavigationMesh> p_nav_mesh, + Ref<NavigationMesh> p_navigation_mesh, #ifdef TOOLS_ENABLED EditorProgress *ep, #endif @@ -75,8 +75,8 @@ public: NavigationMeshGenerator(); ~NavigationMeshGenerator(); - void bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node); - void clear(Ref<NavigationMesh> p_nav_mesh); + void bake(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node); + void clear(Ref<NavigationMesh> p_navigation_mesh); }; #endif diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index 844423afc0..71fcd3ce7f 100644 --- a/modules/openxr/editor/openxr_action_map_editor.cpp +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -205,11 +205,12 @@ void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) { action_map->set_edited(true); } -void OpenXRActionMapEditor::_on_action_removed() { +void OpenXRActionMapEditor::_on_action_removed(Ref<OpenXRAction> p_action) { for (int i = 0; i < tabs->get_tab_count(); i++) { // First tab won't be an interaction profile editor, but being thorough.. OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(tabs->get_tab_control(i)); if (interaction_profile_editor) { + interaction_profile_editor->remove_all_bindings_for_action(p_action); } } } diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h index 8e3210a8e9..2ff6ddf785 100644 --- a/modules/openxr/editor/openxr_action_map_editor.h +++ b/modules/openxr/editor/openxr_action_map_editor.h @@ -75,7 +75,7 @@ private: void _on_add_action_set(); void _set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor); void _on_remove_action_set(Object *p_action_set_editor); - void _on_action_removed(); + void _on_action_removed(Ref<OpenXRAction> p_action); void _on_add_interaction_profile(); void _on_interaction_profile_selected(const String p_path); diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp index d3b6945635..7f4da8b312 100644 --- a/modules/openxr/editor/openxr_action_set_editor.cpp +++ b/modules/openxr/editor/openxr_action_set_editor.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "openxr_action_set_editor.h" +#include "editor/editor_node.h" #include "openxr_action_editor.h" void OpenXRActionSetEditor::_bind_methods() { @@ -211,6 +212,7 @@ void OpenXRActionSetEditor::set_focus_on_entry() { } OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) { + undo_redo = EditorNode::get_undo_redo(); action_map = p_action_map; action_set = p_action_set; diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp index ee73f6a5cd..9d8ac76187 100644 --- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp +++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp @@ -124,8 +124,8 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref<Open undo_redo->create_action(TTR("Remove action from interaction profile")); PackedStringArray paths = binding->get_paths(); for (const String &path : paths) { - undo_redo->add_do_method(this, "_remove_binding", p_action, path); - undo_redo->add_undo_method(this, "_add_binding", p_action, path); + undo_redo->add_do_method(this, "_remove_binding", action_name, path); + undo_redo->add_undo_method(this, "_add_binding", action_name, path); } undo_redo->commit_action(false); diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub index 51d75d45b0..37c8a95905 100644 --- a/modules/raycast/SCsub +++ b/modules/raycast/SCsub @@ -68,10 +68,10 @@ if env["builtin_embree"]: if not env.msvc: if env["arch"] in ["x86_64", "x86_32"]: - env_raycast.Append(CPPFLAGS=["-msse2", "-mxsave"]) + env_raycast.Append(CCFLAGS=["-msse2", "-mxsave"]) if env["platform"] == "windows": - env_raycast.Append(CPPFLAGS=["-mstackrealign"]) + env_raycast.Append(CCFLAGS=["-mstackrealign"]) if env["platform"] == "windows": if env.msvc: @@ -92,11 +92,15 @@ if env["builtin_embree"]: env_thirdparty.Append(CPPDEFINES=["__SSE2__", "__SSE__"]) if env["platform"] == "web": - env_thirdparty.Append(CPPFLAGS=["-msimd128"]) + env_thirdparty.Append(CXXFLAGS=["-msimd128"]) if not env.msvc: + # Flags synced with upstream gnu.cmake. + if env["arch"] == "arm64" and env["platform"] == "linuxbsd": + env_thirdparty.Append(CXXFLAGS=["-flax-vector-conversions"]) + env_thirdparty.Append( - CPPFLAGS=[ + CXXFLAGS=[ "-fno-strict-overflow", "-fno-delete-null-pointer-checks", "-fwrapv", diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index 2dba4916a0..b194e7cb3f 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -67,19 +67,12 @@ void ImageLoaderSVG::_replace_color_property(const HashMap<Color, Color> &p_colo } } -Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) { +Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample) { ERR_FAIL_COND_V_MSG(Math::is_zero_approx(p_scale), ERR_INVALID_PARAMETER, "ImageLoaderSVG: Can't load SVG with a scale of 0."); - if (p_color_map.size()) { - _replace_color_property(p_color_map, "stop-color=\"", p_string); - _replace_color_property(p_color_map, "fill=\"", p_string); - _replace_color_property(p_color_map, "stroke=\"", p_string); - } - std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen(); - PackedByteArray bytes = p_string.to_utf8_buffer(); - tvg::Result result = picture->load((const char *)bytes.ptr(), bytes.size(), "svg", true); + tvg::Result result = picture->load((const char *)p_buffer.ptr(), p_buffer.size(), "svg", true); if (result != tvg::Result::Success) { return ERR_INVALID_DATA; } @@ -149,6 +142,18 @@ Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_stri return OK; } +Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) { + if (p_color_map.size()) { + _replace_color_property(p_color_map, "stop-color=\"", p_string); + _replace_color_property(p_color_map, "fill=\"", p_string); + _replace_color_property(p_color_map, "stroke=\"", p_string); + } + + PackedByteArray bytes = p_string.to_utf8_buffer(); + + return create_image_from_utf8_buffer(p_image, bytes, p_scale, p_upsample); +} + void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("svg"); } diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h index 84511f1708..d955a04f1e 100644 --- a/modules/svg/image_loader_svg.h +++ b/modules/svg/image_loader_svg.h @@ -41,6 +41,7 @@ class ImageLoaderSVG : public ImageFormatLoader { public: static void set_forced_color_map(const HashMap<Color, Color> &p_color_map); + Error create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample); Error create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map); virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) override; diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 046973d193..f3e7ae9b83 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -3296,7 +3296,7 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca Point2 cpos = p_pos; cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; - RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range); + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); } else { double scale = _font_get_scale(p_font_rid, p_size); Point2 cpos = p_pos; @@ -3388,7 +3388,7 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R Point2 cpos = p_pos; cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; - RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range); + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); } else { Point2 cpos = p_pos; double scale = _font_get_scale(p_font_rid, p_size); diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 2cee360f42..ea7b7a271b 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -2359,7 +2359,7 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca Point2 cpos = p_pos; cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; - RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range); + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); } else { Point2 cpos = p_pos; double scale = _font_get_scale(p_font_rid, p_size); @@ -2451,7 +2451,7 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R Point2 cpos = p_pos; cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size; Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; - RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range); + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size); } else { Point2 cpos = p_pos; double scale = _font_get_scale(p_font_rid, p_size); diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index 23b70fbc28..ce78b8d20f 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -227,27 +227,23 @@ void DisplayServerIOS::_window_callback(const Callable &p_callable, const Varian // MARK: Touches void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) { - if (!GLOBAL_GET("debug/disable_touch")) { - Ref<InputEventScreenTouch> ev; - ev.instantiate(); - - ev->set_index(p_idx); - ev->set_pressed(p_pressed); - ev->set_position(Vector2(p_x, p_y)); - ev->set_double_tap(p_double_click); - perform_event(ev); - } + Ref<InputEventScreenTouch> ev; + ev.instantiate(); + + ev->set_index(p_idx); + ev->set_pressed(p_pressed); + ev->set_position(Vector2(p_x, p_y)); + ev->set_double_tap(p_double_click); + perform_event(ev); } void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) { - if (!GLOBAL_GET("debug/disable_touch")) { - Ref<InputEventScreenDrag> ev; - ev.instantiate(); - ev->set_index(p_idx); - ev->set_position(Vector2(p_x, p_y)); - ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y)); - perform_event(ev); - } + Ref<InputEventScreenDrag> ev; + ev.instantiate(); + ev->set_index(p_idx); + ev->set_position(Vector2(p_x, p_y)); + ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y)); + perform_event(ev); } void DisplayServerIOS::perform_event(const Ref<InputEvent> &p_event) { @@ -441,7 +437,7 @@ float DisplayServerIOS::screen_get_refresh_rate(int p_screen) const { } float DisplayServerIOS::screen_get_scale(int p_screen) const { - return [UIScreen mainScreen].nativeScale; + return [UIScreen mainScreen].scale; } Vector<DisplayServer::WindowID> DisplayServerIOS::get_window_list() const { diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm index 4537dc2985..19cb914521 100644 --- a/platform/ios/godot_view.mm +++ b/platform/ios/godot_view.mm @@ -151,7 +151,7 @@ static const float earth_gravity = 9.80665; } - (void)godot_commonInit { - self.contentScaleFactor = [UIScreen mainScreen].nativeScale; + self.contentScaleFactor = [UIScreen mainScreen].scale; [self initTouches]; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index a083a98c72..f8633d29ac 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1164,8 +1164,11 @@ bool OS_Windows::set_environment(const String &p_var, const String &p_value) con String OS_Windows::get_stdin_string(bool p_block) { if (p_block) { - char buff[1024]; - return fgets(buff, 1024, stdin); + WCHAR buff[1024]; + DWORD count = 0; + if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) { + return String::utf16((const char16_t *)buff, count); + } } return String(); diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py index 33ca2e8ffa..b522a75a9c 100644 --- a/platform/windows/platform_windows_builders.py +++ b/platform/windows/platform_windows_builders.py @@ -4,18 +4,15 @@ All such functions are invoked in a subprocess on Windows to prevent build flaki """ import os +from detect import get_mingw_bin_prefix from platform_methods import subprocess_main def make_debug_mingw(target, source, env): - mingw_prefix = "" - if env["arch"] == "x86_32": - mingw_prefix = env["mingw_prefix_32"] - else: - mingw_prefix = env["mingw_prefix_64"] - os.system(mingw_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0])) - os.system(mingw_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0])) - os.system(mingw_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0])) + mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) + os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0])) + os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0])) + os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0])) if __name__ == "__main__": diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp index 8de4c281f4..3ec744ff8e 100644 --- a/scene/2d/joint_2d.cpp +++ b/scene/2d/joint_2d.cpp @@ -112,7 +112,7 @@ void Joint2D::_update_joint(bool p_only_free) { ERR_FAIL_COND_MSG(!joint.is_valid(), "Failed to configure the joint."); - PhysicsServer2D::get_singleton()->get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias); + PhysicsServer2D::get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias); ba = body_a->get_rid(); bb = body_b->get_rid(); @@ -188,7 +188,7 @@ void Joint2D::_notification(int p_what) { void Joint2D::set_bias(real_t p_bias) { bias = p_bias; if (joint.is_valid()) { - PhysicsServer2D::get_singleton()->get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias); + PhysicsServer2D::get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias); } } diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 904b6564bd..62afe0d89b 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -70,6 +70,9 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationAgent2D::set_navigation_layer_value); ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationAgent2D::get_navigation_layer_value); + ClassDB::bind_method(D_METHOD("set_path_metadata_flags", "flags"), &NavigationAgent2D::set_path_metadata_flags); + ClassDB::bind_method(D_METHOD("get_path_metadata_flags"), &NavigationAgent2D::get_path_metadata_flags); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent2D::set_navigation_map); ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent2D::get_navigation_map); @@ -79,8 +82,9 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent2D::get_next_location); ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent2D::distance_to_target); ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent2D::set_velocity); - ClassDB::bind_method(D_METHOD("get_nav_path"), &NavigationAgent2D::get_nav_path); - ClassDB::bind_method(D_METHOD("get_nav_path_index"), &NavigationAgent2D::get_nav_path_index); + ClassDB::bind_method(D_METHOD("get_current_navigation_result"), &NavigationAgent2D::get_current_navigation_result); + ClassDB::bind_method(D_METHOD("get_current_navigation_path"), &NavigationAgent2D::get_current_navigation_path); + ClassDB::bind_method(D_METHOD("get_current_navigation_path_index"), &NavigationAgent2D::get_current_navigation_path_index); ClassDB::bind_method(D_METHOD("is_target_reached"), &NavigationAgent2D::is_target_reached); ClassDB::bind_method(D_METHOD("is_target_reachable"), &NavigationAgent2D::is_target_reachable); ClassDB::bind_method(D_METHOD("is_navigation_finished"), &NavigationAgent2D::is_navigation_finished); @@ -94,6 +98,7 @@ void NavigationAgent2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_target_desired_distance", "get_target_desired_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1,suffix:px"), "set_path_max_distance", "get_path_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "path_metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_path_metadata_flags", "get_path_metadata_flags"); ADD_GROUP("Avoidance", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); @@ -105,6 +110,8 @@ void NavigationAgent2D::_bind_methods() { ADD_SIGNAL(MethodInfo("path_changed")); ADD_SIGNAL(MethodInfo("target_reached")); + ADD_SIGNAL(MethodInfo("waypoint_reached", PropertyInfo(Variant::DICTIONARY, "details"))); + ADD_SIGNAL(MethodInfo("link_reached", PropertyInfo(Variant::DICTIONARY, "details"))); ADD_SIGNAL(MethodInfo("navigation_finished")); ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR2, "safe_velocity"))); } @@ -161,7 +168,7 @@ void NavigationAgent2D::_notification(int p_what) { } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - if (agent_parent) { + if (agent_parent && target_position_submitted) { if (avoidance_enabled) { // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used @@ -256,6 +263,14 @@ bool NavigationAgent2D::get_navigation_layer_value(int p_layer_number) const { return get_navigation_layers() & (1 << (p_layer_number - 1)); } +void NavigationAgent2D::set_path_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_path_metadata_flags) { + if (path_metadata_flags == p_path_metadata_flags) { + return; + } + + path_metadata_flags = p_path_metadata_flags; +} + void NavigationAgent2D::set_navigation_map(RID p_navigation_map) { map_override = p_navigation_map; NavigationServer2D::get_singleton()->agent_set_map(agent, map_override); @@ -314,6 +329,7 @@ real_t NavigationAgent2D::get_path_max_distance() { void NavigationAgent2D::set_target_location(Vector2 p_location) { target_location = p_location; + target_position_submitted = true; _request_repath(); } @@ -329,14 +345,10 @@ Vector2 NavigationAgent2D::get_next_location() { ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector2(), "The agent has no parent."); return agent_parent->get_global_position(); } else { - return navigation_path[nav_path_index]; + return navigation_path[navigation_path_index]; } } -const Vector<Vector2> &NavigationAgent2D::get_nav_path() const { - return navigation_result->get_path(); -} - real_t NavigationAgent2D::distance_to_target() const { ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent."); return agent_parent->get_global_position().distance_to(target_location); @@ -402,6 +414,9 @@ void NavigationAgent2D::update_navigation() { if (!agent_parent->is_inside_tree()) { return; } + if (!target_position_submitted) { + return; + } if (update_frame_id == Engine::get_singleton()->get_physics_frames()) { return; } @@ -418,12 +433,12 @@ void NavigationAgent2D::update_navigation() { reload_path = true; } else { // Check if too far from the navigation path - if (nav_path_index > 0) { + if (navigation_path_index > 0) { const Vector<Vector2> &navigation_path = navigation_result->get_path(); Vector2 segment[2]; - segment[0] = navigation_path[nav_path_index - 1]; - segment[1] = navigation_path[nav_path_index]; + segment[0] = navigation_path[navigation_path_index - 1]; + segment[1] = navigation_path[navigation_path_index]; Vector2 p = Geometry2D::get_closest_point_to_segment(origin, segment); if (origin.distance_to(p) >= path_max_distance) { // To faraway, reload path @@ -436,6 +451,7 @@ void NavigationAgent2D::update_navigation() { navigation_query->set_start_position(origin); navigation_query->set_target_position(target_location); navigation_query->set_navigation_layers(navigation_layers); + navigation_query->set_metadata_flags(path_metadata_flags); if (map_override.is_valid()) { navigation_query->set_map(map_override); @@ -445,7 +461,7 @@ void NavigationAgent2D::update_navigation() { NavigationServer2D::get_singleton()->query_path(navigation_query, navigation_result); navigation_finished = false; - nav_path_index = 0; + navigation_path_index = 0; emit_signal(SNAME("path_changed")); } @@ -457,12 +473,57 @@ void NavigationAgent2D::update_navigation() { if (navigation_finished == false) { // Advances to the next far away location. const Vector<Vector2> &navigation_path = navigation_result->get_path(); - while (origin.distance_to(navigation_path[nav_path_index]) < path_desired_distance) { - nav_path_index += 1; - if (nav_path_index == navigation_path.size()) { + const Vector<int32_t> &navigation_path_types = navigation_result->get_path_types(); + const TypedArray<RID> &navigation_path_rids = navigation_result->get_path_rids(); + const Vector<int64_t> &navigation_path_owners = navigation_result->get_path_owner_ids(); + + while (origin.distance_to(navigation_path[navigation_path_index]) < path_desired_distance) { + Dictionary details; + + const Vector2 waypoint = navigation_path[navigation_path_index]; + details[SNAME("location")] = waypoint; + + int waypoint_type = -1; + if (path_metadata_flags.has_flag(NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_TYPES)) { + const NavigationPathQueryResult2D::PathSegmentType type = NavigationPathQueryResult2D::PathSegmentType(navigation_path_types[navigation_path_index]); + + details[SNAME("type")] = type; + waypoint_type = type; + } + + if (path_metadata_flags.has_flag(NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_RIDS)) { + details[SNAME("rid")] = navigation_path_rids[navigation_path_index]; + } + + if (path_metadata_flags.has_flag(NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_OWNERS)) { + const ObjectID waypoint_owner_id = ObjectID(navigation_path_owners[navigation_path_index]); + + // Get a reference to the owning object. + Object *owner = nullptr; + if (waypoint_owner_id.is_valid()) { + owner = ObjectDB::get_instance(waypoint_owner_id); + } + + details[SNAME("owner")] = owner; + } + + // Emit a signal for the waypoint + emit_signal(SNAME("waypoint_reached"), details); + + // Emit a signal if we've reached a navigation link + if (waypoint_type == NavigationPathQueryResult2D::PATH_SEGMENT_TYPE_LINK) { + emit_signal(SNAME("link_reached"), details); + } + + // Move to the next waypoint on the list + navigation_path_index += 1; + + // Check to see if we've finished our route + if (navigation_path_index == navigation_path.size()) { _check_distance_to_target(); - nav_path_index -= 1; + navigation_path_index -= 1; navigation_finished = true; + target_position_submitted = false; emit_signal(SNAME("navigation_finished")); break; } diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 5abd3c0317..439192cce7 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -32,10 +32,10 @@ #define NAVIGATION_AGENT_2D_H #include "scene/main/node.h" +#include "servers/navigation/navigation_path_query_parameters_2d.h" +#include "servers/navigation/navigation_path_query_result_2d.h" class Node2D; -class NavigationPathQueryParameters2D; -class NavigationPathQueryResult2D; class NavigationAgent2D : public Node { GDCLASS(NavigationAgent2D, Node); @@ -48,6 +48,7 @@ class NavigationAgent2D : public Node { bool avoidance_enabled = false; uint32_t navigation_layers = 1; + BitField<NavigationPathQueryParameters2D::PathMetadataFlags> path_metadata_flags = NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_ALL; real_t path_desired_distance = 1.0; real_t target_desired_distance = 1.0; @@ -60,9 +61,10 @@ class NavigationAgent2D : public Node { real_t path_max_distance = 3.0; Vector2 target_location; + bool target_position_submitted = false; Ref<NavigationPathQueryParameters2D> navigation_query; Ref<NavigationPathQueryResult2D> navigation_result; - int nav_path_index = 0; + int navigation_path_index = 0; bool velocity_submitted = false; Vector2 prev_safe_velocity; /// The submitted target velocity @@ -95,6 +97,11 @@ public: void set_navigation_layer_value(int p_layer_number, bool p_value); bool get_navigation_layer_value(int p_layer_number) const; + void set_path_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_flags); + BitField<NavigationPathQueryParameters2D::PathMetadataFlags> get_path_metadata_flags() const { + return path_metadata_flags; + } + void set_navigation_map(RID p_navigation_map); RID get_navigation_map() const; @@ -141,10 +148,14 @@ public: Vector2 get_next_location(); - const Vector<Vector2> &get_nav_path() const; - - int get_nav_path_index() const { - return nav_path_index; + Ref<NavigationPathQueryResult2D> get_current_navigation_result() const { + return navigation_result; + } + const Vector<Vector2> &get_current_navigation_path() const { + return navigation_result->get_path(); + } + int get_current_navigation_path_index() const { + return navigation_path_index; } real_t distance_to_target() const; diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 7bf3eec79b..675ef7c780 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -31,333 +31,10 @@ #include "navigation_region_2d.h" #include "core/core_string_names.h" -#include "core/math/geometry_2d.h" -#include "core/os/mutex.h" #include "scene/resources/world_2d.h" #include "servers/navigation_server_2d.h" #include "servers/navigation_server_3d.h" -#include "thirdparty/misc/polypartition.h" - -#ifdef TOOLS_ENABLED -Rect2 NavigationPolygon::_edit_get_rect() const { - if (rect_cache_dirty) { - item_rect = Rect2(); - bool first = true; - - for (int i = 0; i < outlines.size(); i++) { - const Vector<Vector2> &outline = outlines[i]; - const int outline_size = outline.size(); - if (outline_size < 3) { - continue; - } - const Vector2 *p = outline.ptr(); - for (int j = 0; j < outline_size; j++) { - if (first) { - item_rect = Rect2(p[j], Vector2(0, 0)); - first = false; - } else { - item_rect.expand_to(p[j]); - } - } - } - - rect_cache_dirty = false; - } - return item_rect; -} - -bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - for (int i = 0; i < outlines.size(); i++) { - const Vector<Vector2> &outline = outlines[i]; - const int outline_size = outline.size(); - if (outline_size < 3) { - continue; - } - if (Geometry2D::is_point_in_polygon(p_point, Variant(outline))) { - return true; - } - } - return false; -} -#endif - -void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) { - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } - vertices = p_vertices; - rect_cache_dirty = true; -} - -Vector<Vector2> NavigationPolygon::get_vertices() const { - return vertices; -} - -void NavigationPolygon::_set_polygons(const TypedArray<Vector<int32_t>> &p_array) { - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } - polygons.resize(p_array.size()); - for (int i = 0; i < p_array.size(); i++) { - polygons.write[i].indices = p_array[i]; - } -} - -TypedArray<Vector<int32_t>> NavigationPolygon::_get_polygons() const { - TypedArray<Vector<int32_t>> ret; - ret.resize(polygons.size()); - for (int i = 0; i < ret.size(); i++) { - ret[i] = polygons[i].indices; - } - - return ret; -} - -void NavigationPolygon::_set_outlines(const TypedArray<Vector<Vector2>> &p_array) { - outlines.resize(p_array.size()); - for (int i = 0; i < p_array.size(); i++) { - outlines.write[i] = p_array[i]; - } - rect_cache_dirty = true; -} - -TypedArray<Vector<Vector2>> NavigationPolygon::_get_outlines() const { - TypedArray<Vector<Vector2>> ret; - ret.resize(outlines.size()); - for (int i = 0; i < ret.size(); i++) { - ret[i] = outlines[i]; - } - - return ret; -} - -void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) { - Polygon polygon; - polygon.indices = p_polygon; - polygons.push_back(polygon); - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } -} - -void NavigationPolygon::add_outline_at_index(const Vector<Vector2> &p_outline, int p_index) { - outlines.insert(p_index, p_outline); - rect_cache_dirty = true; -} - -int NavigationPolygon::get_polygon_count() const { - return polygons.size(); -} - -Vector<int> NavigationPolygon::get_polygon(int p_idx) { - ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>()); - return polygons[p_idx].indices; -} - -void NavigationPolygon::clear_polygons() { - polygons.clear(); - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } -} - -Ref<NavigationMesh> NavigationPolygon::get_mesh() { - MutexLock lock(navmesh_generation); - - if (navmesh.is_null()) { - navmesh.instantiate(); - Vector<Vector3> verts; - { - verts.resize(get_vertices().size()); - Vector3 *w = verts.ptrw(); - - const Vector2 *r = get_vertices().ptr(); - - for (int i(0); i < get_vertices().size(); i++) { - w[i] = Vector3(r[i].x, 0.0, r[i].y); - } - } - navmesh->set_vertices(verts); - - for (int i(0); i < get_polygon_count(); i++) { - navmesh->add_polygon(get_polygon(i)); - } - } - - return navmesh; -} - -void NavigationPolygon::add_outline(const Vector<Vector2> &p_outline) { - outlines.push_back(p_outline); - rect_cache_dirty = true; -} - -int NavigationPolygon::get_outline_count() const { - return outlines.size(); -} - -void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) { - ERR_FAIL_INDEX(p_idx, outlines.size()); - outlines.write[p_idx] = p_outline; - rect_cache_dirty = true; -} - -void NavigationPolygon::remove_outline(int p_idx) { - ERR_FAIL_INDEX(p_idx, outlines.size()); - outlines.remove_at(p_idx); - rect_cache_dirty = true; -} - -Vector<Vector2> NavigationPolygon::get_outline(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, outlines.size(), Vector<Vector2>()); - return outlines[p_idx]; -} - -void NavigationPolygon::clear_outlines() { - outlines.clear(); - rect_cache_dirty = true; -} - -void NavigationPolygon::make_polygons_from_outlines() { - { - MutexLock lock(navmesh_generation); - navmesh.unref(); - } - List<TPPLPoly> in_poly, out_poly; - - Vector2 outside_point(-1e10, -1e10); - - for (int i = 0; i < outlines.size(); i++) { - Vector<Vector2> ol = outlines[i]; - int olsize = ol.size(); - if (olsize < 3) { - continue; - } - const Vector2 *r = ol.ptr(); - for (int j = 0; j < olsize; j++) { - outside_point.x = MAX(r[j].x, outside_point.x); - outside_point.y = MAX(r[j].y, outside_point.y); - } - } - - outside_point += Vector2(0.7239784, 0.819238); //avoid precision issues - - for (int i = 0; i < outlines.size(); i++) { - Vector<Vector2> ol = outlines[i]; - int olsize = ol.size(); - if (olsize < 3) { - continue; - } - const Vector2 *r = ol.ptr(); - - int interscount = 0; - //test if this is an outer outline - for (int k = 0; k < outlines.size(); k++) { - if (i == k) { - continue; //no self intersect - } - - Vector<Vector2> ol2 = outlines[k]; - int olsize2 = ol2.size(); - if (olsize2 < 3) { - continue; - } - const Vector2 *r2 = ol2.ptr(); - - for (int l = 0; l < olsize2; l++) { - if (Geometry2D::segment_intersects_segment(r[0], outside_point, r2[l], r2[(l + 1) % olsize2], nullptr)) { - interscount++; - } - } - } - - bool outer = (interscount % 2) == 0; - - TPPLPoly tp; - tp.Init(olsize); - for (int j = 0; j < olsize; j++) { - tp[j] = r[j]; - } - - if (outer) { - tp.SetOrientation(TPPL_ORIENTATION_CCW); - } else { - tp.SetOrientation(TPPL_ORIENTATION_CW); - tp.SetHole(true); - } - - in_poly.push_back(tp); - } - - TPPLPartition tpart; - if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed! - ERR_PRINT("NavigationPolygon: Convex partition failed! Failed to convert outlines to a valid NavigationMesh." - "\nNavigationPolygon outlines can not overlap vertices or edges inside same outline or with other outlines or have any intersections." - "\nAdd the outmost and largest outline first. To add holes inside this outline add the smaller outlines with opposite winding order."); - return; - } - - polygons.clear(); - vertices.clear(); - - HashMap<Vector2, int> points; - for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) { - TPPLPoly &tp = I->get(); - - struct Polygon p; - - for (int64_t i = 0; i < tp.GetNumPoints(); i++) { - HashMap<Vector2, int>::Iterator E = points.find(tp[i]); - if (!E) { - E = points.insert(tp[i], vertices.size()); - vertices.push_back(tp[i]); - } - p.indices.push_back(E->value); - } - - polygons.push_back(p); - } - - emit_signal(CoreStringNames::get_singleton()->changed); -} - -void NavigationPolygon::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices); - ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices); - - ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationPolygon::add_polygon); - ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count); - ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon); - ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons); - ClassDB::bind_method(D_METHOD("get_mesh"), &NavigationPolygon::get_mesh); - - ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline); - ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index); - ClassDB::bind_method(D_METHOD("get_outline_count"), &NavigationPolygon::get_outline_count); - ClassDB::bind_method(D_METHOD("set_outline", "idx", "outline"), &NavigationPolygon::set_outline); - ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline); - ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline); - ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines); - ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines); - - ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons); - ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons); - - ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines); - ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines); - - ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines"); -} - -///////////////////////////// - void NavigationRegion2D::set_enabled(bool p_enabled) { if (enabled == p_enabled) { return; @@ -460,11 +137,11 @@ RID NavigationRegion2D::get_region_rid() const { #ifdef TOOLS_ENABLED Rect2 NavigationRegion2D::_edit_get_rect() const { - return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2(); + return navigation_polygon.is_valid() ? navigation_polygon->_edit_get_rect() : Rect2(); } bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false; + return navigation_polygon.is_valid() ? navigation_polygon->_edit_is_selected_on_click(p_point, p_tolerance) : false; } #endif @@ -490,8 +167,8 @@ void NavigationRegion2D::_notification(int p_what) { case NOTIFICATION_DRAW: { #ifdef DEBUG_ENABLED - if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) && navpoly.is_valid()) { - Vector<Vector2> verts = navpoly->get_vertices(); + if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) && navigation_polygon.is_valid()) { + Vector<Vector2> verts = navigation_polygon->get_vertices(); if (verts.size() < 3) { return; } @@ -506,9 +183,9 @@ void NavigationRegion2D::_notification(int p_what) { RandomPCG rand; - for (int i = 0; i < navpoly->get_polygon_count(); i++) { + for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) { // An array of vertices for this polygon. - Vector<int> polygon = navpoly->get_polygon(i); + Vector<int> polygon = navigation_polygon->get_polygon(i); Vector<Vector2> vertices; vertices.resize(polygon.size()); for (int j = 0; j < polygon.size(); j++) { @@ -549,36 +226,36 @@ void NavigationRegion2D::_notification(int p_what) { } } -void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly) { - if (p_navpoly == navpoly) { +void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_navigation_polygon) { + if (p_navigation_polygon == navigation_polygon) { return; } - if (navpoly.is_valid()) { - navpoly->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed)); + if (navigation_polygon.is_valid()) { + navigation_polygon->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed)); } - navpoly = p_navpoly; - NavigationServer2D::get_singleton()->region_set_navpoly(region, p_navpoly); + navigation_polygon = p_navigation_polygon; + NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, p_navigation_polygon); - if (navpoly.is_valid()) { - navpoly->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navpoly_changed)); + if (navigation_polygon.is_valid()) { + navigation_polygon->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed)); } - _navpoly_changed(); + _navigation_polygon_changed(); update_configuration_warnings(); } Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const { - return navpoly; + return navigation_polygon; } -void NavigationRegion2D::_navpoly_changed() { +void NavigationRegion2D::_navigation_polygon_changed() { if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) { queue_redraw(); } - if (navpoly.is_valid()) { - NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly); + if (navigation_polygon.is_valid()) { + NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, navigation_polygon); } } @@ -594,7 +271,7 @@ PackedStringArray NavigationRegion2D::get_configuration_warnings() const { PackedStringArray warnings = Node2D::get_configuration_warnings(); if (is_visible_in_tree() && is_inside_tree()) { - if (!navpoly.is_valid()) { + if (!navigation_polygon.is_valid()) { warnings.push_back(RTR("A NavigationMesh resource must be set or created for this node to work. Please set a property or draw a polygon.")); } } @@ -603,7 +280,7 @@ PackedStringArray NavigationRegion2D::get_configuration_warnings() const { } void NavigationRegion2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navpoly"), &NavigationRegion2D::set_navigation_polygon); + ClassDB::bind_method(D_METHOD("set_navigation_polygon", "navigation_polygon"), &NavigationRegion2D::set_navigation_polygon); ClassDB::bind_method(D_METHOD("get_navigation_polygon"), &NavigationRegion2D::get_navigation_polygon); ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion2D::set_enabled); @@ -623,15 +300,34 @@ void NavigationRegion2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion2D::set_travel_cost); ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion2D::get_travel_cost); - ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed); + ClassDB::bind_method(D_METHOD("_navigation_polygon_changed"), &NavigationRegion2D::_navigation_polygon_changed); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_polygon", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost"); } +#ifndef DISABLE_DEPRECATED +// Compatibility with earlier 4.0 betas. +bool NavigationRegion2D::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "navpoly") { + set_navigation_polygon(p_value); + return true; + } + return false; +} + +bool NavigationRegion2D::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "navpoly") { + r_ret = get_navigation_polygon(); + return true; + } + return false; +} +#endif // DISABLE_DEPRECATED + NavigationRegion2D::NavigationRegion2D() { set_notify_transform(true); diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index c630e20780..45029fd95f 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -31,65 +31,7 @@ #ifndef NAVIGATION_REGION_2D_H #define NAVIGATION_REGION_2D_H -#include "scene/2d/node_2d.h" -#include "scene/resources/navigation_mesh.h" - -class NavigationPolygon : public Resource { - GDCLASS(NavigationPolygon, Resource); - - Vector<Vector2> vertices; - struct Polygon { - Vector<int> indices; - }; - Vector<Polygon> polygons; - Vector<Vector<Vector2>> outlines; - - mutable Rect2 item_rect; - mutable bool rect_cache_dirty = true; - - Mutex navmesh_generation; - // Navigation mesh - Ref<NavigationMesh> navmesh; - -protected: - static void _bind_methods(); - - void _set_polygons(const TypedArray<Vector<int32_t>> &p_array); - TypedArray<Vector<int32_t>> _get_polygons() const; - - void _set_outlines(const TypedArray<Vector<Vector2>> &p_array); - TypedArray<Vector<Vector2>> _get_outlines() const; - -public: -#ifdef TOOLS_ENABLED - Rect2 _edit_get_rect() const; - bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; -#endif - - void set_vertices(const Vector<Vector2> &p_vertices); - Vector<Vector2> get_vertices() const; - - void add_polygon(const Vector<int> &p_polygon); - int get_polygon_count() const; - - void add_outline(const Vector<Vector2> &p_outline); - void add_outline_at_index(const Vector<Vector2> &p_outline, int p_index); - void set_outline(int p_idx, const Vector<Vector2> &p_outline); - Vector<Vector2> get_outline(int p_idx) const; - void remove_outline(int p_idx); - int get_outline_count() const; - - void clear_outlines(); - void make_polygons_from_outlines(); - - Vector<int> get_polygon(int p_idx); - void clear_polygons(); - - Ref<NavigationMesh> get_mesh(); - - NavigationPolygon() {} - ~NavigationPolygon() {} -}; +#include "scene/resources/navigation_polygon.h" class NavigationRegion2D : public Node2D { GDCLASS(NavigationRegion2D, Node2D); @@ -99,15 +41,20 @@ class NavigationRegion2D : public Node2D { uint32_t navigation_layers = 1; real_t enter_cost = 0.0; real_t travel_cost = 1.0; - Ref<NavigationPolygon> navpoly; + Ref<NavigationPolygon> navigation_polygon; - void _navpoly_changed(); + void _navigation_polygon_changed(); void _map_changed(RID p_RID); protected: void _notification(int p_what); static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; +#endif // DISABLE_DEPRECATED + public: #ifdef TOOLS_ENABLED virtual Rect2 _edit_get_rect() const override; @@ -131,7 +78,7 @@ public: void set_travel_cost(real_t p_travel_cost); real_t get_travel_cost() const; - void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly); + void set_navigation_polygon(const Ref<NavigationPolygon> &p_navigation_polygon); Ref<NavigationPolygon> get_navigation_polygon() const; PackedStringArray get_configuration_warnings() const override; diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 4788a1b813..166bc26848 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -149,6 +149,10 @@ void Node2D::set_rotation(real_t p_radians) { _update_transform(); } +void Node2D::set_rotation_degrees(real_t p_degrees) { + set_rotation(Math::deg_to_rad(p_degrees)); +} + void Node2D::set_skew(real_t p_radians) { if (_xform_dirty) { const_cast<Node2D *>(this)->_update_xform_values(); @@ -187,6 +191,10 @@ real_t Node2D::get_rotation() const { return rotation; } +real_t Node2D::get_rotation_degrees() const { + return Math::rad_to_deg(get_rotation()); +} + real_t Node2D::get_skew() const { if (_xform_dirty) { const_cast<Node2D *>(this)->_update_xform_values(); @@ -259,6 +267,10 @@ real_t Node2D::get_global_rotation() const { return get_global_transform().get_rotation(); } +real_t Node2D::get_global_rotation_degrees() const { + return Math::rad_to_deg(get_global_rotation()); +} + real_t Node2D::get_global_skew() const { return get_global_transform().get_skew(); } @@ -276,6 +288,10 @@ void Node2D::set_global_rotation(const real_t p_radians) { } } +void Node2D::set_global_rotation_degrees(const real_t p_degrees) { + set_global_rotation(Math::deg_to_rad(p_degrees)); +} + void Node2D::set_global_skew(const real_t p_radians) { CanvasItem *parent = get_parent_item(); if (parent) { @@ -372,11 +388,13 @@ void Node2D::_notification(int p_notification) { void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_position", "position"), &Node2D::set_position); ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Node2D::set_rotation); + ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Node2D::set_rotation_degrees); ClassDB::bind_method(D_METHOD("set_skew", "radians"), &Node2D::set_skew); ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Node2D::set_scale); ClassDB::bind_method(D_METHOD("get_position"), &Node2D::get_position); ClassDB::bind_method(D_METHOD("get_rotation"), &Node2D::get_rotation); + ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Node2D::get_rotation_degrees); ClassDB::bind_method(D_METHOD("get_skew"), &Node2D::get_skew); ClassDB::bind_method(D_METHOD("get_scale"), &Node2D::get_scale); @@ -390,7 +408,9 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_global_position", "position"), &Node2D::set_global_position); ClassDB::bind_method(D_METHOD("get_global_position"), &Node2D::get_global_position); ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node2D::set_global_rotation); + ClassDB::bind_method(D_METHOD("set_global_rotation_degrees", "degrees"), &Node2D::set_global_rotation_degrees); ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node2D::get_global_rotation); + ClassDB::bind_method(D_METHOD("get_global_rotation_degrees"), &Node2D::get_global_rotation_degrees); ClassDB::bind_method(D_METHOD("set_global_skew", "radians"), &Node2D::set_global_skew); ClassDB::bind_method(D_METHOD("get_global_skew"), &Node2D::get_global_skew); ClassDB::bind_method(D_METHOD("set_global_scale", "scale"), &Node2D::set_global_scale); @@ -410,12 +430,14 @@ void Node2D::_bind_methods() { ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_less,or_greater,hide_slider,suffix:px"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation_degrees", "get_global_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_scale", "get_global_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_skew", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_skew", "get_global_skew"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 76707dc422..b066332dcb 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -73,6 +73,7 @@ public: void set_position(const Point2 &p_pos); void set_rotation(real_t p_radians); + void set_rotation_degrees(real_t p_degrees); void set_skew(real_t p_radians); void set_scale(const Size2 &p_scale); @@ -85,11 +86,13 @@ public: Point2 get_position() const; real_t get_rotation() const; + real_t get_rotation_degrees() const; real_t get_skew() const; Size2 get_scale() const; Point2 get_global_position() const; real_t get_global_rotation() const; + real_t get_global_rotation_degrees() const; real_t get_global_skew() const; Size2 get_global_scale() const; @@ -97,6 +100,7 @@ public: void set_global_transform(const Transform2D &p_transform); void set_global_position(const Point2 &p_pos); void set_global_rotation(const real_t p_radians); + void set_global_rotation_degrees(const real_t p_degrees); void set_global_skew(const real_t p_radians); void set_global_scale(const Size2 &p_scale); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index ad70559986..3136752a2e 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1728,10 +1728,10 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List q.navigation_regions[E_cell].resize(tile_set->get_navigation_layers_count()); for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) { - Ref<NavigationPolygon> navpoly; - navpoly = tile_data->get_navigation_polygon(layer_index); + Ref<NavigationPolygon> navigation_polygon; + navigation_polygon = tile_data->get_navigation_polygon(layer_index); - if (navpoly.is_valid()) { + if (navigation_polygon.is_valid()) { Transform2D tile_transform; tile_transform.set_origin(map_to_local(E_cell)); @@ -1739,7 +1739,8 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List NavigationServer2D::get_singleton()->region_set_owner_id(region, get_instance_id()); NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform); - NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly); + NavigationServer2D::get_singleton()->region_set_navigation_layers(region, tile_set->get_navigation_layer_layers(layer_index)); + NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, navigation_polygon); q.navigation_regions[E_cell].write[layer_index] = region; } } @@ -3904,35 +3905,26 @@ void TileMap::draw_cells_outline(Control *p_control, const RBSet<Vector2i> &p_ce DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 2, 3); DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 3, 0); DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 0, 1); + } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 2, 3); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 3, 0); } else { if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0); - } else { - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5); - } + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5); } else { - if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3); - } else { - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2); - DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3); - } + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3); } } } diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index ef381641ab..2729dfc369 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -34,6 +34,7 @@ #include "physics_body_3d.h" #include "scene/resources/concave_polygon_shape_3d.h" #include "scene/resources/convex_polygon_shape_3d.h" +#include "scene/resources/world_boundary_shape_3d.h" void CollisionShape3D::make_convex_from_siblings() { Node *p = get_parent(); @@ -125,10 +126,12 @@ PackedStringArray CollisionShape3D::get_configuration_warnings() const { warnings.push_back(RTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.")); } - if (shape.is_valid() && - Object::cast_to<RigidBody3D>(get_parent()) && - Object::cast_to<ConcavePolygonShape3D>(*shape)) { - warnings.push_back(RTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.")); + if (shape.is_valid() && Object::cast_to<RigidBody3D>(get_parent())) { + if (Object::cast_to<ConcavePolygonShape3D>(*shape)) { + warnings.push_back(RTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.")); + } else if (Object::cast_to<WorldBoundaryShape3D>(*shape)) { + warnings.push_back(RTR("WorldBoundaryShape3D doesn't support RigidBody3D in another mode than static.")); + } } return warnings; diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index 16de95bfb1..c4ec54fa8f 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -53,18 +53,7 @@ bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) { if (p_name.operator String().begins_with("surface_material_override/")) { int idx = p_name.operator String().get_slicec('/', 1).to_int(); - // This is a bit of a hack to ensure compatibility with material - // overrides that start indexing at 1. - // We assume that idx 0 is always read first, if its not, this won't work. - if (idx == 0) { - surface_index_0 = true; - } - if (!surface_index_0) { - // This means the file was created when the indexing started at 1, so decrease by one. - idx--; - } - - if (idx > surface_override_materials.size() || idx < 0) { + if (idx >= surface_override_materials.size() || idx < 0) { return false; } diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index e907b9f66f..741f7397ad 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -74,6 +74,9 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationAgent3D::set_navigation_layer_value); ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationAgent3D::get_navigation_layer_value); + ClassDB::bind_method(D_METHOD("set_path_metadata_flags", "flags"), &NavigationAgent3D::set_path_metadata_flags); + ClassDB::bind_method(D_METHOD("get_path_metadata_flags"), &NavigationAgent3D::get_path_metadata_flags); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent3D::set_navigation_map); ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent3D::get_navigation_map); @@ -83,8 +86,9 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent3D::get_next_location); ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent3D::distance_to_target); ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent3D::set_velocity); - ClassDB::bind_method(D_METHOD("get_nav_path"), &NavigationAgent3D::get_nav_path); - ClassDB::bind_method(D_METHOD("get_nav_path_index"), &NavigationAgent3D::get_nav_path_index); + ClassDB::bind_method(D_METHOD("get_current_navigation_result"), &NavigationAgent3D::get_current_navigation_result); + ClassDB::bind_method(D_METHOD("get_current_navigation_path"), &NavigationAgent3D::get_current_navigation_path); + ClassDB::bind_method(D_METHOD("get_current_navigation_path_index"), &NavigationAgent3D::get_current_navigation_path_index); ClassDB::bind_method(D_METHOD("is_target_reached"), &NavigationAgent3D::is_target_reached); ClassDB::bind_method(D_METHOD("is_target_reachable"), &NavigationAgent3D::is_target_reachable); ClassDB::bind_method(D_METHOD("is_navigation_finished"), &NavigationAgent3D::is_navigation_finished); @@ -99,6 +103,7 @@ void NavigationAgent3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01,suffix:m"), "set_agent_height_offset", "get_agent_height_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,suffix:m"), "set_path_max_distance", "get_path_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "path_metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_path_metadata_flags", "get_path_metadata_flags"); ADD_GROUP("Avoidance", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); @@ -111,6 +116,8 @@ void NavigationAgent3D::_bind_methods() { ADD_SIGNAL(MethodInfo("path_changed")); ADD_SIGNAL(MethodInfo("target_reached")); + ADD_SIGNAL(MethodInfo("waypoint_reached", PropertyInfo(Variant::DICTIONARY, "details"))); + ADD_SIGNAL(MethodInfo("link_reached", PropertyInfo(Variant::DICTIONARY, "details"))); ADD_SIGNAL(MethodInfo("navigation_finished")); ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity"))); } @@ -167,7 +174,7 @@ void NavigationAgent3D::_notification(int p_what) { } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - if (agent_parent) { + if (agent_parent && target_position_submitted) { if (avoidance_enabled) { // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used @@ -263,6 +270,14 @@ bool NavigationAgent3D::get_navigation_layer_value(int p_layer_number) const { return get_navigation_layers() & (1 << (p_layer_number - 1)); } +void NavigationAgent3D::set_path_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_path_metadata_flags) { + if (path_metadata_flags == p_path_metadata_flags) { + return; + } + + path_metadata_flags = p_path_metadata_flags; +} + void NavigationAgent3D::set_navigation_map(RID p_navigation_map) { map_override = p_navigation_map; NavigationServer3D::get_singleton()->agent_set_map(agent, map_override); @@ -330,6 +345,7 @@ real_t NavigationAgent3D::get_path_max_distance() { void NavigationAgent3D::set_target_location(Vector3 p_location) { target_location = p_location; + target_position_submitted = true; _request_repath(); } @@ -345,14 +361,10 @@ Vector3 NavigationAgent3D::get_next_location() { ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector3(), "The agent has no parent."); return agent_parent->get_global_transform().origin; } else { - return navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0); + return navigation_path[navigation_path_index] - Vector3(0, navigation_height_offset, 0); } } -const Vector<Vector3> &NavigationAgent3D::get_nav_path() const { - return navigation_result->get_path(); -} - real_t NavigationAgent3D::distance_to_target() const { ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent."); return agent_parent->get_global_transform().origin.distance_to(target_location); @@ -417,6 +429,9 @@ void NavigationAgent3D::update_navigation() { if (!agent_parent->is_inside_tree()) { return; } + if (!target_position_submitted) { + return; + } if (update_frame_id == Engine::get_singleton()->get_physics_frames()) { return; } @@ -433,12 +448,12 @@ void NavigationAgent3D::update_navigation() { reload_path = true; } else { // Check if too far from the navigation path - if (nav_path_index > 0) { + if (navigation_path_index > 0) { const Vector<Vector3> &navigation_path = navigation_result->get_path(); Vector3 segment[2]; - segment[0] = navigation_path[nav_path_index - 1]; - segment[1] = navigation_path[nav_path_index]; + segment[0] = navigation_path[navigation_path_index - 1]; + segment[1] = navigation_path[navigation_path_index]; segment[0].y -= navigation_height_offset; segment[1].y -= navigation_height_offset; Vector3 p = Geometry3D::get_closest_point_to_segment(origin, segment); @@ -453,6 +468,7 @@ void NavigationAgent3D::update_navigation() { navigation_query->set_start_position(origin); navigation_query->set_target_position(target_location); navigation_query->set_navigation_layers(navigation_layers); + navigation_query->set_metadata_flags(path_metadata_flags); if (map_override.is_valid()) { navigation_query->set_map(map_override); @@ -462,7 +478,7 @@ void NavigationAgent3D::update_navigation() { NavigationServer3D::get_singleton()->query_path(navigation_query, navigation_result); navigation_finished = false; - nav_path_index = 0; + navigation_path_index = 0; emit_signal(SNAME("path_changed")); } @@ -474,12 +490,57 @@ void NavigationAgent3D::update_navigation() { if (navigation_finished == false) { // Advances to the next far away location. const Vector<Vector3> &navigation_path = navigation_result->get_path(); - while (origin.distance_to(navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0)) < path_desired_distance) { - nav_path_index += 1; - if (nav_path_index == navigation_path.size()) { + const Vector<int32_t> &navigation_path_types = navigation_result->get_path_types(); + const TypedArray<RID> &navigation_path_rids = navigation_result->get_path_rids(); + const Vector<int64_t> &navigation_path_owners = navigation_result->get_path_owner_ids(); + + while (origin.distance_to(navigation_path[navigation_path_index] - Vector3(0, navigation_height_offset, 0)) < path_desired_distance) { + Dictionary details; + + const Vector3 waypoint = navigation_path[navigation_path_index]; + details[SNAME("location")] = waypoint; + + int waypoint_type = -1; + if (path_metadata_flags.has_flag(NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_TYPES)) { + const NavigationPathQueryResult3D::PathSegmentType type = NavigationPathQueryResult3D::PathSegmentType(navigation_path_types[navigation_path_index]); + + details[SNAME("type")] = type; + waypoint_type = type; + } + + if (path_metadata_flags.has_flag(NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_RIDS)) { + details[SNAME("rid")] = navigation_path_rids[navigation_path_index]; + } + + if (path_metadata_flags.has_flag(NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_OWNERS)) { + const ObjectID waypoint_owner_id = ObjectID(navigation_path_owners[navigation_path_index]); + + // Get a reference to the owning object. + Object *owner = nullptr; + if (waypoint_owner_id.is_valid()) { + owner = ObjectDB::get_instance(waypoint_owner_id); + } + + details[SNAME("owner")] = owner; + } + + // Emit a signal for the waypoint + emit_signal(SNAME("waypoint_reached"), details); + + // Emit a signal if we've reached a navigation link + if (waypoint_type == NavigationPathQueryResult3D::PATH_SEGMENT_TYPE_LINK) { + emit_signal(SNAME("link_reached"), details); + } + + // Move to the next waypoint on the list + navigation_path_index += 1; + + // Check to see if we've finished our route + if (navigation_path_index == navigation_path.size()) { _check_distance_to_target(); - nav_path_index -= 1; + navigation_path_index -= 1; navigation_finished = true; + target_position_submitted = false; emit_signal(SNAME("navigation_finished")); break; } diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index 90ceab0242..cda218b538 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -32,10 +32,10 @@ #define NAVIGATION_AGENT_3D_H #include "scene/main/node.h" +#include "servers/navigation/navigation_path_query_parameters_3d.h" +#include "servers/navigation/navigation_path_query_result_3d.h" class Node3D; -class NavigationPathQueryParameters3D; -class NavigationPathQueryResult3D; class NavigationAgent3D : public Node { GDCLASS(NavigationAgent3D, Node); @@ -48,6 +48,7 @@ class NavigationAgent3D : public Node { bool avoidance_enabled = false; uint32_t navigation_layers = 1; + BitField<NavigationPathQueryParameters3D::PathMetadataFlags> path_metadata_flags = NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_ALL; real_t path_desired_distance = 1.0; real_t target_desired_distance = 1.0; @@ -62,9 +63,10 @@ class NavigationAgent3D : public Node { real_t path_max_distance = 3.0; Vector3 target_location; + bool target_position_submitted = false; Ref<NavigationPathQueryParameters3D> navigation_query; Ref<NavigationPathQueryResult3D> navigation_result; - int nav_path_index = 0; + int navigation_path_index = 0; bool velocity_submitted = false; Vector3 prev_safe_velocity; /// The submitted target velocity @@ -97,6 +99,11 @@ public: void set_navigation_layer_value(int p_layer_number, bool p_value); bool get_navigation_layer_value(int p_layer_number) const; + void set_path_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_flags); + BitField<NavigationPathQueryParameters3D::PathMetadataFlags> get_path_metadata_flags() const { + return path_metadata_flags; + } + void set_navigation_map(RID p_navigation_map); RID get_navigation_map() const; @@ -153,10 +160,14 @@ public: Vector3 get_next_location(); - const Vector<Vector3> &get_nav_path() const; - - int get_nav_path_index() const { - return nav_path_index; + Ref<NavigationPathQueryResult3D> get_current_navigation_result() const { + return navigation_result; + } + const Vector<Vector3> &get_current_navigation_path() const { + return navigation_result->get_path(); + } + int get_current_navigation_path_index() const { + return navigation_path_index; } real_t distance_to_target() const; diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index bd96c55512..86b78f847e 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -192,26 +192,26 @@ void NavigationRegion3D::_notification(int p_what) { } } -void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh) { - if (p_navmesh == navmesh) { +void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navigation_mesh) { + if (p_navigation_mesh == navigation_mesh) { return; } - if (navmesh.is_valid()) { - navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); + if (navigation_mesh.is_valid()) { + navigation_mesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); } - navmesh = p_navmesh; + navigation_mesh = p_navigation_mesh; - if (navmesh.is_valid()) { - navmesh->connect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); + if (navigation_mesh.is_valid()) { + navigation_mesh->connect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); } - NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh); + NavigationServer3D::get_singleton()->region_set_navigation_mesh(region, p_navigation_mesh); #ifdef DEBUG_ENABLED if (is_inside_tree() && NavigationServer3D::get_singleton()->get_debug_enabled()) { - if (navmesh.is_valid()) { + if (navigation_mesh.is_valid()) { _update_debug_mesh(); _update_debug_edge_connections_mesh(); } else { @@ -232,7 +232,7 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes } Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const { - return navmesh; + return navigation_mesh; } struct BakeThreadsArgs { @@ -245,7 +245,7 @@ void _bake_navigation_mesh(void *p_user_data) { if (args->nav_region->get_navigation_mesh().is_valid()) { Ref<NavigationMesh> nav_mesh = args->nav_region->get_navigation_mesh()->duplicate(); - NavigationServer3D::get_singleton()->region_bake_navmesh(nav_mesh, args->nav_region); + NavigationServer3D::get_singleton()->region_bake_navigation_mesh(nav_mesh, args->nav_region); args->nav_region->call_deferred(SNAME("_bake_finished"), nav_mesh); memdelete(args); } else { @@ -278,7 +278,7 @@ PackedStringArray NavigationRegion3D::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible_in_tree() && is_inside_tree()) { - if (!navmesh.is_valid()) { + if (!navigation_mesh.is_valid()) { warnings.push_back(RTR("A NavigationMesh resource must be set or created for this node to work.")); } } @@ -287,7 +287,7 @@ PackedStringArray NavigationRegion3D::get_configuration_warnings() const { } void NavigationRegion3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navmesh"), &NavigationRegion3D::set_navigation_mesh); + ClassDB::bind_method(D_METHOD("set_navigation_mesh", "navigation_mesh"), &NavigationRegion3D::set_navigation_mesh); ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationRegion3D::get_navigation_mesh); ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion3D::set_enabled); @@ -308,9 +308,9 @@ void NavigationRegion3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion3D::get_travel_cost); ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationRegion3D::bake_navigation_mesh, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion3D::_bake_finished); + ClassDB::bind_method(D_METHOD("_bake_finished", "navigation_mesh"), &NavigationRegion3D::_bake_finished); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_mesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost"); @@ -320,6 +320,25 @@ void NavigationRegion3D::_bind_methods() { ADD_SIGNAL(MethodInfo("bake_finished")); } +#ifndef DISABLE_DEPRECATED +// Compatibility with earlier 4.0 betas. +bool NavigationRegion3D::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "navmesh") { + set_navigation_mesh(p_value); + return true; + } + return false; +} + +bool NavigationRegion3D::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "navmesh") { + r_ret = get_navigation_mesh(); + return true; + } + return false; +} +#endif // DISABLE_DEPRECATED + void NavigationRegion3D::_navigation_changed() { update_gizmos(); update_configuration_warnings(); @@ -353,8 +372,8 @@ NavigationRegion3D::NavigationRegion3D() { } NavigationRegion3D::~NavigationRegion3D() { - if (navmesh.is_valid()) { - navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); + if (navigation_mesh.is_valid()) { + navigation_mesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); } NavigationServer3D::get_singleton()->free(region); @@ -392,7 +411,7 @@ void NavigationRegion3D::_update_debug_mesh() { return; } - if (!navmesh.is_valid()) { + if (!navigation_mesh.is_valid()) { if (debug_instance.is_valid()) { RS::get_singleton()->instance_set_visible(debug_instance, false); } @@ -412,12 +431,12 @@ void NavigationRegion3D::_update_debug_mesh() { bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color(); bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines(); - Vector<Vector3> vertices = navmesh->get_vertices(); + Vector<Vector3> vertices = navigation_mesh->get_vertices(); if (vertices.size() == 0) { return; } - int polygon_count = navmesh->get_polygon_count(); + int polygon_count = navigation_mesh->get_polygon_count(); if (polygon_count == 0) { return; } @@ -450,7 +469,7 @@ void NavigationRegion3D::_update_debug_mesh() { polygon_color.a = debug_navigation_geometry_face_color.a; } - Vector<int> polygon = navmesh->get_polygon(i); + Vector<int> polygon = navigation_mesh->get_polygon(i); face_vertex_array.push_back(vertices[polygon[0]]); face_vertex_array.push_back(vertices[polygon[1]]); @@ -528,7 +547,7 @@ void NavigationRegion3D::_update_debug_edge_connections_mesh() { return; } - if (!navmesh.is_valid()) { + if (!navigation_mesh.is_valid()) { if (debug_edge_connections_instance.is_valid()) { RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false); } diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 660538d314..811c0885a1 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -42,7 +42,7 @@ class NavigationRegion3D : public Node3D { uint32_t navigation_layers = 1; real_t enter_cost = 0.0; real_t travel_cost = 1.0; - Ref<NavigationMesh> navmesh; + Ref<NavigationMesh> navigation_mesh; Thread bake_thread; @@ -64,6 +64,11 @@ protected: void _notification(int p_what); static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; +#endif // DISABLE_DEPRECATED + public: void set_enabled(bool p_enabled); bool is_enabled() const; @@ -82,13 +87,13 @@ public: void set_travel_cost(real_t p_travel_cost); real_t get_travel_cost() const; - void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh); + void set_navigation_mesh(const Ref<NavigationMesh> &p_navigation_mesh); Ref<NavigationMesh> get_navigation_mesh() const; /// Bakes the navigation mesh; once done, automatically /// sets the new navigation mesh and emits a signal void bake_navigation_mesh(bool p_on_thread); - void _bake_finished(Ref<NavigationMesh> p_nav_mesh); + void _bake_finished(Ref<NavigationMesh> p_navigation_mesh); PackedStringArray get_configuration_warnings() const override; diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index a60ccd2169..32bbea8ff3 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -251,12 +251,22 @@ Vector3 Node3D::get_global_rotation() const { return get_global_transform().get_basis().get_euler(); } +Vector3 Node3D::get_global_rotation_degrees() const { + Vector3 radians = get_global_rotation(); + return Vector3(Math::rad_to_deg(radians.x), Math::rad_to_deg(radians.y), Math::rad_to_deg(radians.z)); +} + void Node3D::set_global_rotation(const Vector3 &p_euler_rad) { Transform3D transform = get_global_transform(); transform.basis = Basis::from_euler(p_euler_rad); set_global_transform(transform); } +void Node3D::set_global_rotation_degrees(const Vector3 &p_euler_degrees) { + Vector3 radians(Math::deg_to_rad(p_euler_degrees.x), Math::deg_to_rad(p_euler_degrees.y), Math::deg_to_rad(p_euler_degrees.z)); + set_global_rotation(radians); +} + void Node3D::set_transform(const Transform3D &p_transform) { data.local_transform = p_transform; data.dirty = DIRTY_EULER_ROTATION_AND_SCALE; // Make rot/scale dirty. @@ -440,6 +450,11 @@ void Node3D::set_rotation(const Vector3 &p_euler_rad) { } } +void Node3D::set_rotation_degrees(const Vector3 &p_euler_degrees) { + Vector3 radians(Math::deg_to_rad(p_euler_degrees.x), Math::deg_to_rad(p_euler_degrees.y), Math::deg_to_rad(p_euler_degrees.z)); + set_rotation(radians); +} + void Node3D::set_scale(const Vector3 &p_scale) { if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) { // Update rotation only if rotation and scale are dirty, as scale will be overridden. @@ -467,6 +482,11 @@ Vector3 Node3D::get_rotation() const { return data.euler_rotation; } +Vector3 Node3D::get_rotation_degrees() const { + Vector3 radians = get_rotation(); + return Vector3(Math::rad_to_deg(radians.x), Math::rad_to_deg(radians.y), Math::rad_to_deg(radians.z)); +} + Vector3 Node3D::get_scale() const { if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) { _update_rotation_and_scale(); @@ -958,8 +978,10 @@ void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_transform"), &Node3D::get_transform); ClassDB::bind_method(D_METHOD("set_position", "position"), &Node3D::set_position); ClassDB::bind_method(D_METHOD("get_position"), &Node3D::get_position); - ClassDB::bind_method(D_METHOD("set_rotation", "euler"), &Node3D::set_rotation); + ClassDB::bind_method(D_METHOD("set_rotation", "euler_radians"), &Node3D::set_rotation); ClassDB::bind_method(D_METHOD("get_rotation"), &Node3D::get_rotation); + ClassDB::bind_method(D_METHOD("set_rotation_degrees", "euler_degrees"), &Node3D::set_rotation_degrees); + ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Node3D::get_rotation_degrees); ClassDB::bind_method(D_METHOD("set_rotation_order", "order"), &Node3D::set_rotation_order); ClassDB::bind_method(D_METHOD("get_rotation_order"), &Node3D::get_rotation_order); ClassDB::bind_method(D_METHOD("set_rotation_edit_mode", "edit_mode"), &Node3D::set_rotation_edit_mode); @@ -975,8 +997,10 @@ void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_transform"), &Node3D::get_global_transform); ClassDB::bind_method(D_METHOD("set_global_position", "position"), &Node3D::set_global_position); ClassDB::bind_method(D_METHOD("get_global_position"), &Node3D::get_global_position); - ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node3D::set_global_rotation); + ClassDB::bind_method(D_METHOD("set_global_rotation", "euler_radians"), &Node3D::set_global_rotation); ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node3D::get_global_rotation); + ClassDB::bind_method(D_METHOD("set_global_rotation_degrees", "euler_degrees"), &Node3D::set_global_rotation_degrees); + ClassDB::bind_method(D_METHOD("get_global_rotation_degrees"), &Node3D::get_global_rotation_degrees); ClassDB::bind_method(D_METHOD("get_parent_node_3d"), &Node3D::get_parent_node_3d); ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification); @@ -1045,6 +1069,7 @@ void Node3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_less,hide_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_HIDE_QUATERNION_EDIT, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion"); ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); @@ -1054,6 +1079,7 @@ void Node3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation_degrees", "get_global_rotation_degrees"); ADD_GROUP("Visibility", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "visibility_parent", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GeometryInstance3D"), "set_visibility_parent", "get_visibility_parent"); diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 76c1e3e22c..9558a978fd 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -172,19 +172,23 @@ public: void set_rotation_order(EulerOrder p_order); void set_rotation(const Vector3 &p_euler_rad); + void set_rotation_degrees(const Vector3 &p_euler_degrees); void set_scale(const Vector3 &p_scale); void set_global_position(const Vector3 &p_position); void set_global_rotation(const Vector3 &p_euler_rad); + void set_global_rotation_degrees(const Vector3 &p_euler_degrees); Vector3 get_position() const; EulerOrder get_rotation_order() const; Vector3 get_rotation() const; + Vector3 get_rotation_degrees() const; Vector3 get_scale() const; Vector3 get_global_position() const; Vector3 get_global_rotation() const; + Vector3 get_global_rotation_degrees() const; void set_transform(const Transform3D &p_transform); void set_basis(const Basis &p_basis); diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index c027e33ad3..3b21f5c03a 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -102,6 +102,24 @@ bool VisualInstance3D::get_layer_mask_value(int p_layer_number) const { return layers & (1 << (p_layer_number - 1)); } +void VisualInstance3D::set_sorting_offset(float p_offset) { + sorting_offset = p_offset; + RenderingServer::get_singleton()->instance_set_pivot_data(instance, sorting_offset, sorting_use_aabb_center); +} + +float VisualInstance3D::get_sorting_offset() const { + return sorting_offset; +} + +void VisualInstance3D::set_sorting_use_aabb_center(bool p_enabled) { + sorting_use_aabb_center = p_enabled; + RenderingServer::get_singleton()->instance_set_pivot_data(instance, sorting_offset, sorting_use_aabb_center); +} + +bool VisualInstance3D::is_sorting_use_aabb_center() const { + return sorting_use_aabb_center; +} + void VisualInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance3D::set_base); ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance3D::get_base); @@ -110,9 +128,17 @@ void VisualInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance3D::get_layer_mask); ClassDB::bind_method(D_METHOD("set_layer_mask_value", "layer_number", "value"), &VisualInstance3D::set_layer_mask_value); ClassDB::bind_method(D_METHOD("get_layer_mask_value", "layer_number"), &VisualInstance3D::get_layer_mask_value); + ClassDB::bind_method(D_METHOD("set_sorting_offset", "offset"), &VisualInstance3D::set_sorting_offset); + ClassDB::bind_method(D_METHOD("get_sorting_offset"), &VisualInstance3D::get_sorting_offset); + ClassDB::bind_method(D_METHOD("set_sorting_use_aabb_center", "enabled"), &VisualInstance3D::set_sorting_use_aabb_center); + ClassDB::bind_method(D_METHOD("is_sorting_use_aabb_center"), &VisualInstance3D::is_sorting_use_aabb_center); GDVIRTUAL_BIND(_get_aabb); ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask"); + + ADD_GROUP("Sorting", "sorting_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sorting_offset"), "set_sorting_offset", "get_sorting_offset"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sorting_use_aabb_center"), "set_sorting_use_aabb_center", "is_sorting_use_aabb_center"); } void VisualInstance3D::set_base(const RID &p_base) { diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index c741ef710d..2d107f61d2 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -39,6 +39,8 @@ class VisualInstance3D : public Node3D { RID base; RID instance; uint32_t layers = 1; + float sorting_offset = 0.0; + bool sorting_use_aabb_center = true; protected: void _update_visibility(); @@ -67,6 +69,12 @@ public: void set_layer_mask_value(int p_layer_number, bool p_enable); bool get_layer_mask_value(int p_layer_number) const; + void set_sorting_offset(float p_offset); + float get_sorting_offset() const; + + void set_sorting_use_aabb_center(bool p_enabled); + bool is_sorting_use_aabb_center() const; + VisualInstance3D(); ~VisualInstance3D(); }; diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 6200062f60..26261d6da5 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -144,6 +144,19 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_ext } } } + + // Emit start & finish signal. Internally, the detections are the same for backward. + // We should use call_deferred since the track keys are still being prosessed. + if (state->tree) { + // AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection. + if (p_seek && !p_is_external_seeking && cur_time == 0) { + state->tree->call_deferred(SNAME("emit_signal"), "animation_started", animation); + } + // Finished. + if (prev_time < anim_size && cur_time >= anim_size) { + state->tree->call_deferred(SNAME("emit_signal"), "animation_finished", animation); + } + } } if (play_mode == PLAY_MODE_FORWARD) { @@ -351,7 +364,7 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter } else { main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - blend, FILTER_BLEND, sync); // Unlike below, processing this edge is a corner case. } - double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, MAX(CMP_EPSILON, blend), FILTER_PASS, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_PASS, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. if (do_start) { cur_remaining = os_rem; @@ -769,17 +782,18 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex } // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + real_t blend_inv = 1.0 - blend; if (from_start && !p_seek && switched) { //just switched, seek to start of current - rem = blend_input(cur_current, 0, true, p_is_external_seeking, MAX(CMP_EPSILON, 1.0 - blend), FILTER_IGNORE, true); + rem = blend_input(cur_current, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true); } else { - rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, MAX(CMP_EPSILON, 1.0 - blend), FILTER_IGNORE, true); + rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true); } if (p_seek) { - blend_input(cur_prev, p_time, true, p_is_external_seeking, MAX(CMP_EPSILON, blend), FILTER_IGNORE, true); + blend_input(cur_prev, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true); cur_time = p_time; } else { - blend_input(cur_prev, p_time, false, p_is_external_seeking, MAX(CMP_EPSILON, blend), FILTER_IGNORE, true); + blend_input(cur_prev, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true); cur_time += p_time; cur_prev_xfading -= p_time; if (cur_prev_xfading < 0) { diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index d3746c1144..d54740e9b0 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -41,12 +41,12 @@ AnimationNodeStateMachineTransition::SwitchMode AnimationNodeStateMachineTransit return switch_mode; } -void AnimationNodeStateMachineTransition::set_auto_advance(bool p_enable) { - auto_advance = p_enable; +void AnimationNodeStateMachineTransition::set_advance_mode(AdvanceMode p_mode) { + advance_mode = p_mode; } -bool AnimationNodeStateMachineTransition::has_auto_advance() const { - return auto_advance; +AnimationNodeStateMachineTransition::AdvanceMode AnimationNodeStateMachineTransition::get_advance_mode() const { + return advance_mode; } void AnimationNodeStateMachineTransition::set_advance_condition(const StringName &p_condition) { @@ -107,15 +107,6 @@ Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const { return xfade_curve; } -void AnimationNodeStateMachineTransition::set_disabled(bool p_disabled) { - disabled = p_disabled; - emit_changed(); -} - -bool AnimationNodeStateMachineTransition::is_disabled() const { - return disabled; -} - void AnimationNodeStateMachineTransition::set_priority(int p_priority) { priority = p_priority; emit_changed(); @@ -129,8 +120,8 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_switch_mode", "mode"), &AnimationNodeStateMachineTransition::set_switch_mode); ClassDB::bind_method(D_METHOD("get_switch_mode"), &AnimationNodeStateMachineTransition::get_switch_mode); - ClassDB::bind_method(D_METHOD("set_auto_advance", "auto_advance"), &AnimationNodeStateMachineTransition::set_auto_advance); - ClassDB::bind_method(D_METHOD("has_auto_advance"), &AnimationNodeStateMachineTransition::has_auto_advance); + ClassDB::bind_method(D_METHOD("set_advance_mode", "mode"), &AnimationNodeStateMachineTransition::set_advance_mode); + ClassDB::bind_method(D_METHOD("get_advance_mode"), &AnimationNodeStateMachineTransition::get_advance_mode); ClassDB::bind_method(D_METHOD("set_advance_condition", "name"), &AnimationNodeStateMachineTransition::set_advance_condition); ClassDB::bind_method(D_METHOD("get_advance_condition"), &AnimationNodeStateMachineTransition::get_advance_condition); @@ -141,9 +132,6 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve); ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve); - ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &AnimationNodeStateMachineTransition::set_disabled); - ClassDB::bind_method(D_METHOD("is_disabled"), &AnimationNodeStateMachineTransition::is_disabled); - ClassDB::bind_method(D_METHOD("set_priority", "priority"), &AnimationNodeStateMachineTransition::set_priority); ClassDB::bind_method(D_METHOD("get_priority"), &AnimationNodeStateMachineTransition::get_priority); @@ -155,17 +143,19 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority"); ADD_GROUP("Switch", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_advance"), "set_auto_advance", "has_auto_advance"); ADD_GROUP("Advance", "advance_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "advance_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Auto"), "set_advance_mode", "get_advance_mode"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "advance_condition"), "set_advance_condition", "get_advance_condition"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "advance_expression", PROPERTY_HINT_EXPRESSION, ""), "set_advance_expression", "get_advance_expression"); - ADD_GROUP("Disabling", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); BIND_ENUM_CONSTANT(SWITCH_MODE_IMMEDIATE); BIND_ENUM_CONSTANT(SWITCH_MODE_SYNC); BIND_ENUM_CONSTANT(SWITCH_MODE_AT_END); + BIND_ENUM_CONSTANT(ADVANCE_MODE_DISABLED); + BIND_ENUM_CONSTANT(ADVANCE_MODE_ENABLED); + BIND_ENUM_CONSTANT(ADVANCE_MODE_AUTO); + ADD_SIGNAL(MethodInfo("advance_condition_changed")); } @@ -234,7 +224,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta //build open list for (int i = 0; i < p_state_machine->transitions.size(); i++) { - if (p_state_machine->transitions[i].transition->is_disabled()) { + if (p_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) { continue; } @@ -279,7 +269,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta StringName transition = p_state_machine->transitions[least_cost_transition->get()].local_to; for (int i = 0; i < p_state_machine->transitions.size(); i++) { - if (p_state_machine->transitions[i].transition->is_disabled()) { + if (p_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) { continue; } @@ -379,6 +369,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s // can't travel, then teleport path.clear(); current = start_request; + play_start = true; } start_request = StringName(); //clear start request } @@ -424,7 +415,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s fading_pos += p_time; } fade_blend = MIN(1.0, fading_pos / fading_time); - if (fade_blend >= 1.0) { + if (fade_blend > 1.0) { fading_from = StringName(); } } @@ -433,10 +424,11 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s if (current_curve.is_valid()) { fade_blend = current_curve->sample(fade_blend); } - float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, MAX(CMP_EPSILON, fade_blend), AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + double rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + double fade_blend_inv = 1.0 - fade_blend; if (fading_from != StringName()) { - p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, MAX(CMP_EPSILON, 1.0 - fade_blend), AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend_inv) ? CMP_EPSILON : fade_blend_inv, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. } //guess playback position @@ -445,19 +437,19 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s } { //advance and loop check - float next_pos = len_current - rem; + double next_pos = len_current - rem; end_loop = next_pos < pos_current; pos_current = next_pos; //looped } //find next StringName next; - float next_xfade = 0.0; + double next_xfade = 0.0; AnimationNodeStateMachineTransition::SwitchMode switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE; if (path.size()) { for (int i = 0; i < p_state_machine->transitions.size(); i++) { - if (p_state_machine->transitions[i].transition->is_disabled()) { + if (p_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) { continue; } @@ -473,7 +465,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s int auto_advance_to = -1; for (int i = 0; i < p_state_machine->transitions.size(); i++) { - if (p_state_machine->transitions[i].transition->is_disabled()) { + if (p_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) { continue; } @@ -541,7 +533,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s int auto_advance_to = -1; for (int i = 0; i < prev_state_machine->transitions.size(); i++) { - if (prev_state_machine->transitions[i].transition->is_disabled()) { + if (prev_state_machine->transitions[i].transition->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED) { continue; } @@ -628,14 +620,14 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s } bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<AnimationNodeStateMachine> state_machine, const Ref<AnimationNodeStateMachineTransition> transition) const { - if (transition->has_auto_advance()) { - return true; + if (transition->get_advance_mode() != AnimationNodeStateMachineTransition::ADVANCE_MODE_AUTO) { + return false; } StringName advance_condition_name = transition->get_advance_condition_name(); - if (advance_condition_name != StringName() && bool(state_machine->get_parameter(advance_condition_name))) { - return true; + if (advance_condition_name != StringName() && !bool(state_machine->get_parameter(advance_condition_name))) { + return false; } if (transition->expression.is_valid()) { @@ -645,20 +637,18 @@ bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<Anima NodePath advance_expression_base_node_path = tree_base->get_advance_expression_base_node(); Node *expression_base = tree_base->get_node_or_null(advance_expression_base_node_path); - WARN_PRINT_ONCE("Animation transition has a valid expression, but no expression base node was set on its AnimationTree."); - if (expression_base) { Ref<Expression> exp = transition->expression; bool ret = exp->execute(Array(), expression_base, false, Engine::get_singleton()->is_editor_hint()); // Avoids allowing the user to crash the system with an expression by only allowing const calls. - if (!exp->has_execute_failed()) { - if (ret) { - return true; - } + if (exp->has_execute_failed() || !ret) { + return false; } + } else { + WARN_PRINT_ONCE("Animation transition has a valid expression, but no expression base node was set on its AnimationTree."); } } - return false; + return true; } void AnimationNodeStateMachinePlayback::_bind_methods() { @@ -834,7 +824,8 @@ void AnimationNodeStateMachine::rename_node(const StringName &p_name, const Stri _rename_transitions(p_name, p_new_name); - emit_signal("tree_changed"); + emit_changed(); + emit_signal(SNAME("tree_changed")); } void AnimationNodeStateMachine::_rename_transitions(const StringName &p_name, const StringName &p_new_name) { @@ -877,9 +868,8 @@ void AnimationNodeStateMachine::_rename_transitions(const StringName &p_name, co transitions.write[i].to = p_new_name; } - - updating_transitions = false; } + updating_transitions = false; } void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const { @@ -1291,6 +1281,7 @@ Vector2 AnimationNodeStateMachine::get_node_position(const StringName &p_name) c } void AnimationNodeStateMachine::_tree_changed() { + emit_changed(); emit_signal(SNAME("tree_changed")); } diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index 0dfe5a3a43..83b5e66491 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -44,14 +44,19 @@ public: SWITCH_MODE_AT_END, }; + enum AdvanceMode { + ADVANCE_MODE_DISABLED, + ADVANCE_MODE_ENABLED, + ADVANCE_MODE_AUTO, + }; + private: SwitchMode switch_mode = SWITCH_MODE_IMMEDIATE; - bool auto_advance = false; + AdvanceMode advance_mode = ADVANCE_MODE_ENABLED; StringName advance_condition; StringName advance_condition_name; float xfade_time = 0.0; Ref<Curve> xfade_curve; - bool disabled = false; int priority = 1; String advance_expression; @@ -65,8 +70,8 @@ public: void set_switch_mode(SwitchMode p_mode); SwitchMode get_switch_mode() const; - void set_auto_advance(bool p_enable); - bool has_auto_advance() const; + void set_advance_mode(AdvanceMode p_mode); + AdvanceMode get_advance_mode() const; void set_advance_condition(const StringName &p_condition); StringName get_advance_condition() const; @@ -82,9 +87,6 @@ public: void set_xfade_curve(const Ref<Curve> &p_curve); Ref<Curve> get_xfade_curve() const; - void set_disabled(bool p_disabled); - bool is_disabled() const; - void set_priority(int p_priority); int get_priority() const; @@ -92,6 +94,7 @@ public: }; VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode) +VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::AdvanceMode) class AnimationNodeStateMachine; @@ -111,8 +114,8 @@ class AnimationNodeStateMachinePlayback : public Resource { StringName next; }; - float len_current = 0.0; - float pos_current = 0.0; + double len_current = 0.0; + double pos_current = 0.0; bool end_loop = false; StringName current; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index cc6fadd9b2..ff20724f89 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -691,7 +691,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } } else { if (p_started) { - int first_key = a->track_find_key(i, p_prev_time, true); + int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT); if (first_key >= 0) { indices.push_back(first_key); } @@ -761,7 +761,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } } else { if (p_started) { - int first_key = a->track_find_key(i, p_prev_time, true); + int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT); if (first_key >= 0) { indices.push_back(first_key); } @@ -855,7 +855,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double //find stuff to play List<int> to_play; if (p_started) { - int first_key = a->track_find_key(i, p_prev_time, true); + int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT); if (first_key >= 0) { to_play.push_back(first_key); } @@ -968,7 +968,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double //find stuff to play List<int> to_play; if (p_started) { - int first_key = a->track_find_key(i, p_prev_time, true); + int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT); if (first_key >= 0) { to_play.push_back(first_key); } @@ -1072,25 +1072,34 @@ void AnimationPlayer::_animation_process2(double p_delta, bool p_started) { accum_pass++; bool seeked = c.seeked; // The animation may be changed during process, so it is safer that the state is changed before process. + if (p_delta != 0) { c.seeked = false; } - _animation_process_data(c.current, p_delta, 1.0f, seeked, p_started); + float blend = 1.0; // First animation we play at 100% blend - List<Blend>::Element *prev = nullptr; - for (List<Blend>::Element *E = c.blend.back(); E; E = prev) { + List<Blend>::Element *next = NULL; + for (List<Blend>::Element *E = c.blend.front(); E; E = next) { Blend &b = E->get(); - float blend = b.blend_left / b.blend_time; + // Note: There may be issues if an animation event triggers an animation change while this blend is active, + // so it is best to use "deferred" calls instead of "immediate" for animation events that can trigger new animations. + _animation_process_data(b.data, p_delta, blend, false, false); + blend = 1.0 - b.blend_left / b.blend_time; // This is how much to blend the NEXT animation b.blend_left -= Math::absf(speed_scale * p_delta); - prev = E->prev(); + next = E->next(); if (b.blend_left < 0) { - c.blend.erase(E); + // If the blend of this has finished, we need to remove ALL the previous blends + List<Blend>::Element *prev; + while (E) { + prev = E->prev(); + c.blend.erase(E); + E = prev; + } } - // The effect of animation changes during blending is unknown... - // In that case, we recommends to use method call mode "deferred", not "immediate". - _animation_process_data(b.data, p_delta, blend, false, false); } + + _animation_process_data(c.current, p_delta, blend, seeked, p_started); } void AnimationPlayer::_animation_update_transforms() { @@ -1643,6 +1652,8 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa b.data = c.current; b.blend_time = b.blend_left = blend_time; c.blend.push_back(b); + } else { + c.blend.clear(); } } diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index b06a21dea9..b3408c1509 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -432,7 +432,6 @@ void AnimationNode::_bind_methods() { GDVIRTUAL_BIND(_has_filter); ADD_SIGNAL(MethodInfo("removed_from_graph")); - ADD_SIGNAL(MethodInfo("tree_changed")); BIND_ENUM_CONSTANT(FILTER_IGNORE); @@ -1383,7 +1382,7 @@ void AnimationTree::_process_graph(double p_delta) { } } else { if (seeked) { - int idx = a->track_find_key(i, time, !is_external_seeking); + int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT); if (idx < 0) { continue; } @@ -1406,7 +1405,7 @@ void AnimationTree::_process_graph(double p_delta) { TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track); if (seeked) { - int idx = a->track_find_key(i, time, !is_external_seeking); + int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT); if (idx < 0) { continue; } @@ -1440,7 +1439,7 @@ void AnimationTree::_process_graph(double p_delta) { if (seeked) { //find whatever should be playing - int idx = a->track_find_key(i, time, !is_external_seeking); + int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT); if (idx < 0) { continue; } @@ -1553,7 +1552,7 @@ void AnimationTree::_process_graph(double p_delta) { if (seeked) { //seek - int idx = a->track_find_key(i, time, !is_external_seeking); + int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT); if (idx < 0) { continue; } @@ -2037,6 +2036,10 @@ void AnimationTree::_bind_methods() { BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL); ADD_SIGNAL(MethodInfo("animation_player_changed")); + + // Signals from AnimationNodes. + ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name"))); + ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING_NAME, "anim_name"))); } AnimationTree::AnimationTree() { diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index ac9034c6fd..9da1fbda1b 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -300,6 +300,7 @@ void BaseButton::set_toggle_mode(bool p_on) { } toggle_mode = p_on; + update_configuration_warnings(); } bool BaseButton::is_toggle_mode() const { @@ -381,6 +382,7 @@ void BaseButton::set_button_group(const Ref<ButtonGroup> &p_group) { } queue_redraw(); //checkbox changes to radio if set a buttongroup + update_configuration_warnings(); } Ref<ButtonGroup> BaseButton::get_button_group() const { @@ -399,6 +401,16 @@ bool BaseButton::is_shortcut_feedback() const { return shortcut_feedback; } +PackedStringArray BaseButton::get_configuration_warnings() const { + PackedStringArray warnings = Control::get_configuration_warnings(); + + if (get_button_group().is_valid() && !is_toggle_mode()) { + warnings.push_back(RTR("ButtonGroup is intended to be used only with buttons that have toggle_mode set to true.")); + } + + return warnings; +} + void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &BaseButton::set_pressed); ClassDB::bind_method(D_METHOD("is_pressed"), &BaseButton::is_pressed); diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 3acf535f54..5018aea120 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -136,6 +136,8 @@ public: void set_shortcut_feedback(bool p_feedback); bool is_shortcut_feedback() const; + PackedStringArray get_configuration_warnings() const override; + BaseButton(); ~BaseButton(); }; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 3bb02ebf7f..c84438ed5e 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -2081,20 +2081,22 @@ void CodeEdit::confirm_code_completion(bool p_replace) { } char32_t last_completion_char_display = display_text[display_text.length() - 1]; + bool last_char_matches = (last_completion_char == next_char || last_completion_char_display == next_char); int pre_brace_pair = get_caret_column(i) > 0 ? _get_auto_brace_pair_open_at_pos(caret_line, get_caret_column(i)) : -1; int post_brace_pair = get_caret_column(i) < get_line(caret_line).length() ? _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column(i)) : -1; - if (post_brace_pair != -1 && (last_completion_char == next_char || last_completion_char_display == next_char)) { + // Strings do not nest like brackets, so ensure we don't add an additional closing pair. + if (has_string_delimiter(String::chr(last_completion_char)) && post_brace_pair != -1 && last_char_matches) { remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); - } - - if (pre_brace_pair != -1 && pre_brace_pair != post_brace_pair && (last_completion_char == next_char || last_completion_char_display == next_char)) { - remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); - adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); - } else if (auto_brace_completion_enabled && pre_brace_pair != -1 && post_brace_pair == -1) { - insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key, i); - set_caret_column(get_caret_column(i) - auto_brace_completion_pairs[pre_brace_pair].close_key.length(), i == 0, i); + } else { + if (pre_brace_pair != -1 && pre_brace_pair != post_brace_pair && last_char_matches) { + remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); + adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1); + } else if (auto_brace_completion_enabled && pre_brace_pair != -1) { + insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key, i); + set_caret_column(get_caret_column(i) - auto_brace_completion_pairs[pre_brace_pair].close_key.length(), i == 0, i); + } } if (pre_brace_pair == -1 && post_brace_pair == -1 && get_caret_column(i) > 0 && get_caret_column(i) < get_line(caret_line).length()) { diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index eb9f9039b7..fa4b57d7a7 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -1577,8 +1577,7 @@ void ColorPicker::_bind_methods() { BIND_ENUM_CONSTANT(SHAPE_NONE); } -ColorPicker::ColorPicker() : - BoxContainer(true) { +ColorPicker::ColorPicker() { HBoxContainer *hb_edit = memnew(HBoxContainer); add_child(hb_edit, false, INTERNAL_MODE_FRONT); hb_edit->set_v_size_flags(SIZE_SHRINK_BEGIN); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 3208676539..799ca2d202 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -68,8 +68,8 @@ public: ~ColorPresetButton(); }; -class ColorPicker : public BoxContainer { - GDCLASS(ColorPicker, BoxContainer); +class ColorPicker : public VBoxContainer { + GDCLASS(ColorPicker, VBoxContainer); public: enum ColorModeType { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 68af7af5d4..21c7c4ddb4 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1475,10 +1475,18 @@ void Control::set_rotation(real_t p_radians) { _notify_transform(); } +void Control::set_rotation_degrees(real_t p_degrees) { + set_rotation(Math::deg_to_rad(p_degrees)); +} + real_t Control::get_rotation() const { return data.rotation; } +real_t Control::get_rotation_degrees() const { + return Math::rad_to_deg(get_rotation()); +} + void Control::set_pivot_offset(const Vector2 &p_pivot) { if (data.pivot_offset == p_pivot) { return; @@ -3042,6 +3050,7 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("set_global_position", "position", "keep_offsets"), &Control::set_global_position, DEFVAL(false)); ClassDB::bind_method(D_METHOD("_set_global_position", "position"), &Control::_set_global_position); ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Control::set_rotation); + ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Control::set_rotation_degrees); ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Control::set_scale); ClassDB::bind_method(D_METHOD("set_pivot_offset", "pivot_offset"), &Control::set_pivot_offset); ClassDB::bind_method(D_METHOD("get_begin"), &Control::get_begin); @@ -3049,6 +3058,7 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("get_position"), &Control::get_position); ClassDB::bind_method(D_METHOD("get_size"), &Control::get_size); ClassDB::bind_method(D_METHOD("get_rotation"), &Control::get_rotation); + ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Control::get_rotation_degrees); ClassDB::bind_method(D_METHOD("get_scale"), &Control::get_scale); ClassDB::bind_method(D_METHOD("get_pivot_offset"), &Control::get_pivot_offset); ClassDB::bind_method(D_METHOD("get_custom_minimum_size"), &Control::get_custom_minimum_size); @@ -3217,6 +3227,7 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_pivot_offset", "get_pivot_offset"); diff --git a/scene/gui/control.h b/scene/gui/control.h index 12710f3a93..f82fba3b1b 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -451,7 +451,9 @@ public: void set_scale(const Vector2 &p_scale); Vector2 get_scale() const; void set_rotation(real_t p_radians); + void set_rotation_degrees(real_t p_degrees); real_t get_rotation() const; + real_t get_rotation_degrees() const; void set_pivot_offset(const Vector2 &p_pivot); Vector2 get_pivot_offset() const; diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index 7219e86f52..2c43ca7143 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -108,6 +108,14 @@ String LinkButton::get_language() const { return language; } +void LinkButton::set_uri(const String &p_uri) { + uri = p_uri; +} + +String LinkButton::get_uri() const { + return uri; +} + void LinkButton::set_underline_mode(UnderlineMode p_underline_mode) { if (underline_mode == p_underline_mode) { return; @@ -121,6 +129,14 @@ LinkButton::UnderlineMode LinkButton::get_underline_mode() const { return underline_mode; } +void LinkButton::pressed() { + if (uri.is_empty()) { + return; + } + + OS::get_singleton()->shell_open(uri); +} + Size2 LinkButton::get_minimum_size() const { return text_buf->get_size(); } @@ -245,6 +261,8 @@ void LinkButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_text_direction"), &LinkButton::get_text_direction); ClassDB::bind_method(D_METHOD("set_language", "language"), &LinkButton::set_language); ClassDB::bind_method(D_METHOD("get_language"), &LinkButton::get_language); + ClassDB::bind_method(D_METHOD("set_uri", "uri"), &LinkButton::set_uri); + ClassDB::bind_method(D_METHOD("get_uri"), &LinkButton::get_uri); ClassDB::bind_method(D_METHOD("set_underline_mode", "underline_mode"), &LinkButton::set_underline_mode); ClassDB::bind_method(D_METHOD("get_underline_mode"), &LinkButton::get_underline_mode); ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override", "parser"), &LinkButton::set_structured_text_bidi_override); @@ -258,6 +276,7 @@ void LinkButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::INT, "underline", PROPERTY_HINT_ENUM, "Always,On Hover,Never"), "set_underline_mode", "get_underline_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "uri"), "set_uri", "get_uri"); ADD_GROUP("BiDi", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h index accd848163..c71872fc86 100644 --- a/scene/gui/link_button.h +++ b/scene/gui/link_button.h @@ -49,6 +49,7 @@ private: String xl_text; Ref<TextLine> text_buf; UnderlineMode underline_mode = UNDERLINE_MODE_ALWAYS; + String uri; String language; TextDirection text_direction = TEXT_DIRECTION_AUTO; @@ -76,6 +77,7 @@ private: void _shape(); protected: + virtual void pressed() override; virtual Size2 get_minimum_size() const override; virtual void _update_theme_item_cache() override; void _notification(int p_what); @@ -84,6 +86,8 @@ protected: public: void set_text(const String &p_text); String get_text() const; + void set_uri(const String &p_uri); + String get_uri() const; void set_structured_text_bidi_override(TextServer::StructuredTextParser p_parser); TextServer::StructuredTextParser get_structured_text_bidi_override() const; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index a0f2096009..d5c4fd3f07 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -3071,18 +3071,18 @@ void RichTextLabel::add_newline() { queue_redraw(); } -bool RichTextLabel::remove_line(const int p_line) { +bool RichTextLabel::remove_paragraph(const int p_paragraph) { _stop_thread(); MutexLock data_lock(data_mutex); - if (p_line >= (int)current_frame->lines.size() || p_line < 0) { + if (p_paragraph >= (int)current_frame->lines.size() || p_paragraph < 0) { return false; } // Remove all subitems with the same line as that provided. Vector<int> subitem_indices_to_remove; for (int i = 0; i < current->subitems.size(); i++) { - if (current->subitems[i]->line == p_line) { + if (current->subitems[i]->line == p_paragraph) { subitem_indices_to_remove.push_back(i); } } @@ -3092,17 +3092,17 @@ bool RichTextLabel::remove_line(const int p_line) { for (int i = subitem_indices_to_remove.size() - 1; i >= 0; i--) { int subitem_idx = subitem_indices_to_remove[i]; had_newline = had_newline || current->subitems[subitem_idx]->type == ITEM_NEWLINE; - _remove_item(current->subitems[subitem_idx], current->subitems[subitem_idx]->line, p_line); + _remove_item(current->subitems[subitem_idx], current->subitems[subitem_idx]->line, p_paragraph); } if (!had_newline) { - current_frame->lines.remove_at(p_line); + current_frame->lines.remove_at(p_paragraph); if (current_frame->lines.size() == 0) { current_frame->lines.resize(1); } } - if (p_line == 0 && current->subitems.size() > 0) { + if (p_paragraph == 0 && current->subitems.size() > 0) { main->lines[0].from = main; } @@ -3182,7 +3182,8 @@ void RichTextLabel::push_normal() { void RichTextLabel::push_bold() { ERR_FAIL_COND(theme_cache.bold_font.is_null()); - _push_def_font(BOLD_FONT); + ItemFont *item_font = _find_font(current); + _push_def_font((item_font && item_font->def_font == ITALICS_FONT) ? BOLD_ITALICS_FONT : BOLD_FONT); } void RichTextLabel::push_bold_italics() { @@ -3194,7 +3195,8 @@ void RichTextLabel::push_bold_italics() { void RichTextLabel::push_italics() { ERR_FAIL_COND(theme_cache.italics_font.is_null()); - _push_def_font(ITALICS_FONT); + ItemFont *item_font = _find_font(current); + _push_def_font((item_font && item_font->def_font == BOLD_FONT) ? BOLD_ITALICS_FONT : ITALICS_FONT); } void RichTextLabel::push_mono() { @@ -5313,7 +5315,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text); ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align", "region"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(Rect2(0, 0, 0, 0))); ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline); - ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line); + ClassDB::bind_method(D_METHOD("remove_paragraph", "paragraph"), &RichTextLabel::remove_paragraph); ClassDB::bind_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font); ClassDB::bind_method(D_METHOD("push_font_size", "font_size"), &RichTextLabel::push_font_size); ClassDB::bind_method(D_METHOD("push_normal"), &RichTextLabel::push_normal); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 7aa6e6fa2a..a4bc1c8e03 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -573,7 +573,7 @@ public: void add_text(const String &p_text); void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlignment p_alignment = INLINE_ALIGNMENT_CENTER, const Rect2 &p_region = Rect2(0, 0, 0, 0)); void add_newline(); - bool remove_line(const int p_line); + bool remove_paragraph(const int p_paragraph); void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0)); void _push_def_font(DefaultFont p_def_font); void _push_def_font_var(DefaultFont p_def_font, const Ref<Font> &p_font, int p_size = -1); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 35cc29d080..79bad44e15 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3785,7 +3785,9 @@ bool Tree::edit_selected() { } else if (c.mode == TreeItem::CELL_MODE_STRING || c.mode == TreeItem::CELL_MODE_RANGE) { Rect2 popup_rect; - Vector2 ofs(0, Math::floor((text_editor->get_size().height - rect.size.height) / 2)); // "floor()" centers vertically. + int value_editor_height = c.mode == TreeItem::CELL_MODE_RANGE ? value_editor->get_minimum_size().height : 0; + // "floor()" centers vertically. + Vector2 ofs(0, Math::floor((MAX(text_editor->get_minimum_size().height, rect.size.height - value_editor_height) - rect.size.height) / 2)); Point2i textedpos = get_screen_position() + rect.position - ofs; cache.text_editor_position = textedpos; @@ -3801,7 +3803,7 @@ bool Tree::edit_selected() { text_editor->select_all(); if (c.mode == TreeItem::CELL_MODE_RANGE) { - popup_rect.size.y += value_editor->get_minimum_size().height; + popup_rect.size.y += value_editor_height; value_editor->show(); updating_value_editor = true; @@ -5281,7 +5283,6 @@ Tree::Tree() { add_child(popup_menu, false, INTERNAL_MODE_FRONT); popup_editor = memnew(Popup); - popup_editor->set_wrap_controls(true); add_child(popup_editor, false, INTERNAL_MODE_FRONT); popup_editor_vb = memnew(VBoxContainer); popup_editor->add_child(popup_editor_vb); @@ -5290,11 +5291,9 @@ Tree::Tree() { text_editor = memnew(LineEdit); popup_editor_vb->add_child(text_editor); text_editor->set_v_size_flags(SIZE_EXPAND_FILL); - text_editor->set_h_size_flags(SIZE_EXPAND_FILL); value_editor = memnew(HSlider); - value_editor->set_v_size_flags(SIZE_EXPAND_FILL); - value_editor->set_h_size_flags(SIZE_EXPAND_FILL); popup_editor_vb->add_child(value_editor); + value_editor->set_v_size_flags(SIZE_EXPAND_FILL); value_editor->hide(); h_scroll = memnew(HScrollBar); diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 2563fa5914..f3812eb497 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -144,7 +144,7 @@ void CanvasItem::_redraw_callback() { Transform2D CanvasItem::get_global_transform_with_canvas() const { if (canvas_layer) { - return canvas_layer->get_transform() * get_global_transform(); + return canvas_layer->get_final_transform() * get_global_transform(); } else if (is_inside_tree()) { return get_viewport()->get_canvas_transform() * get_global_transform(); } else { @@ -621,10 +621,10 @@ void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv); } -void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range) { +void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range, double p_scale) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); ERR_FAIL_COND(p_texture.is_null()); - RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range); + RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range, p_scale); } void CanvasItem::draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate) { @@ -950,14 +950,14 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_self_modulate", "self_modulate"), &CanvasItem::set_self_modulate); ClassDB::bind_method(D_METHOD("get_self_modulate"), &CanvasItem::get_self_modulate); - ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &Node2D::set_z_index); - ClassDB::bind_method(D_METHOD("get_z_index"), &Node2D::get_z_index); + ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &CanvasItem::set_z_index); + ClassDB::bind_method(D_METHOD("get_z_index"), &CanvasItem::get_z_index); - ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &Node2D::set_z_as_relative); - ClassDB::bind_method(D_METHOD("is_z_relative"), &Node2D::is_z_relative); + ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &CanvasItem::set_z_as_relative); + ClassDB::bind_method(D_METHOD("is_z_relative"), &CanvasItem::is_z_relative); - ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &Node2D::set_y_sort_enabled); - ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &Node2D::is_y_sort_enabled); + ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &CanvasItem::set_y_sort_enabled); + ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &CanvasItem::is_y_sort_enabled); ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent); ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled); @@ -974,7 +974,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0)); + ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range", "scale"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0), DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("draw_lcd_texture_rect_region", "texture", "rect", "src_rect", "modulate"), &CanvasItem::draw_lcd_texture_rect_region, DEFVAL(Color(1, 1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box); ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0)); @@ -1099,7 +1099,7 @@ Transform2D CanvasItem::get_canvas_transform() const { ERR_FAIL_COND_V(!is_inside_tree(), Transform2D()); if (canvas_layer) { - return canvas_layer->get_transform(); + return canvas_layer->get_final_transform(); } else if (Object::cast_to<CanvasItem>(get_parent())) { return Object::cast_to<CanvasItem>(get_parent())->get_canvas_transform(); } else { @@ -1111,7 +1111,7 @@ Transform2D CanvasItem::get_viewport_transform() const { ERR_FAIL_COND_V(!is_inside_tree(), Transform2D()); if (canvas_layer) { - return get_viewport()->get_final_transform() * canvas_layer->get_transform(); + return get_viewport()->get_final_transform() * canvas_layer->get_final_transform(); } else { return get_viewport()->get_final_transform() * get_viewport()->get_canvas_transform(); } diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 4ace982825..bae03d706a 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -259,7 +259,7 @@ public: void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1)); void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false); - void draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0); + void draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0, double p_scale = 1.0); void draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)); void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect); void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), real_t p_width = 1); diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 5fde18721a..97b784e9d0 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -88,6 +88,18 @@ Transform2D CanvasLayer::get_transform() const { return transform; } +Transform2D CanvasLayer::get_final_transform() const { + if (is_following_viewport()) { + Transform2D follow; + follow.scale(Vector2(get_follow_viewport_scale(), get_follow_viewport_scale())); + if (vp) { + follow = vp->get_canvas_transform() * follow; + } + return follow * transform; + } + return transform; +} + void CanvasLayer::_update_xform() { transform.set_rotation_and_scale(rot, scale); transform.set_origin(ofs); @@ -304,6 +316,7 @@ void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transform", "transform"), &CanvasLayer::set_transform); ClassDB::bind_method(D_METHOD("get_transform"), &CanvasLayer::get_transform); + ClassDB::bind_method(D_METHOD("get_final_transform"), &CanvasLayer::get_final_transform); ClassDB::bind_method(D_METHOD("set_offset", "offset"), &CanvasLayer::set_offset); ClassDB::bind_method(D_METHOD("get_offset"), &CanvasLayer::get_offset); diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 74b5ebd453..2afc842a50 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -77,6 +77,7 @@ public: void set_transform(const Transform2D &p_xform); Transform2D get_transform() const; + Transform2D get_final_transform() const; void set_offset(const Vector2 &p_offset); Vector2 get_offset() const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index e17947c27b..e61cca0a0f 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1422,7 +1422,7 @@ SceneTree::SceneTree() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_3d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)"))); root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d)); - const bool transparent_background = GLOBAL_DEF("rendering/transparent_background", false); + const bool transparent_background = GLOBAL_DEF("rendering/viewport/transparent_background", false); root->set_transparent_background(transparent_background); const int ssaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/screen_space_aa", 0); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index fdbcb20d30..afc31ae480 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -642,7 +642,7 @@ void Viewport::_process_picking() { ObjectID canvas_layer_id; if (E) { // A descendant CanvasLayer. - canvas_layer_transform = E->get_transform(); + canvas_layer_transform = E->get_final_transform(); canvas_layer_id = E->get_instance_id(); } else { // This Viewport's builtin canvas. diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 043895b591..4f300cb5d6 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -56,6 +56,7 @@ #include "scene/2d/navigation_agent_2d.h" #include "scene/2d/navigation_link_2d.h" #include "scene/2d/navigation_obstacle_2d.h" +#include "scene/2d/navigation_region_2d.h" #include "scene/2d/parallax_background.h" #include "scene/2d/parallax_layer.h" #include "scene/2d/path_2d.h" @@ -163,6 +164,7 @@ #include "scene/resources/mesh_data_tool.h" #include "scene/resources/multimesh.h" #include "scene/resources/navigation_mesh.h" +#include "scene/resources/navigation_polygon.h" #include "scene/resources/packed_scene.h" #include "scene/resources/particle_process_material.h" #include "scene/resources/physics_material.h" diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 077a53464e..37407edc33 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -1319,7 +1319,7 @@ Error Animation::blend_shape_track_interpolate(int p_track, double p_time, float } void Animation::track_remove_key_at_time(int p_track, double p_time) { - int idx = track_find_key(p_track, p_time, true); + int idx = track_find_key(p_track, p_time, FIND_MODE_APPROX); ERR_FAIL_COND(idx < 0); track_remove_key(p_track, idx); } @@ -1400,7 +1400,7 @@ void Animation::track_remove_key(int p_track, int p_idx) { emit_changed(); } -int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { +int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; @@ -1416,7 +1416,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { uint32_t key_index; bool fetch_compressed_success = _fetch_compressed<3>(tt->compressed_track, p_time, key, time, key_next, time_next, &key_index); ERR_FAIL_COND_V(!fetch_compressed_success, -1); - if (p_exact && time != p_time) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) { return -1; } return key_index; @@ -1426,7 +1426,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { if (k < 0 || k >= tt->positions.size()) { return -1; } - if (tt->positions[k].time != p_time && p_exact) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(tt->positions[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && tt->positions[k].time != p_time)) { return -1; } return k; @@ -1443,7 +1443,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { uint32_t key_index; bool fetch_compressed_success = _fetch_compressed<3>(rt->compressed_track, p_time, key, time, key_next, time_next, &key_index); ERR_FAIL_COND_V(!fetch_compressed_success, -1); - if (p_exact && time != p_time) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) { return -1; } return key_index; @@ -1453,7 +1453,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { if (k < 0 || k >= rt->rotations.size()) { return -1; } - if (rt->rotations[k].time != p_time && p_exact) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(rt->rotations[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && rt->rotations[k].time != p_time)) { return -1; } return k; @@ -1470,7 +1470,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { uint32_t key_index; bool fetch_compressed_success = _fetch_compressed<3>(st->compressed_track, p_time, key, time, key_next, time_next, &key_index); ERR_FAIL_COND_V(!fetch_compressed_success, -1); - if (p_exact && time != p_time) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) { return -1; } return key_index; @@ -1480,7 +1480,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { if (k < 0 || k >= st->scales.size()) { return -1; } - if (st->scales[k].time != p_time && p_exact) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(st->scales[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && st->scales[k].time != p_time)) { return -1; } return k; @@ -1497,7 +1497,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { uint32_t key_index; bool fetch_compressed_success = _fetch_compressed<1>(bst->compressed_track, p_time, key, time, key_next, time_next, &key_index); ERR_FAIL_COND_V(!fetch_compressed_success, -1); - if (p_exact && time != p_time) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) { return -1; } return key_index; @@ -1507,7 +1507,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { if (k < 0 || k >= bst->blend_shapes.size()) { return -1; } - if (bst->blend_shapes[k].time != p_time && p_exact) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(bst->blend_shapes[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && bst->blend_shapes[k].time != p_time)) { return -1; } return k; @@ -1519,7 +1519,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { if (k < 0 || k >= vt->values.size()) { return -1; } - if (vt->values[k].time != p_time && p_exact) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(vt->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && vt->values[k].time != p_time)) { return -1; } return k; @@ -1531,7 +1531,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { if (k < 0 || k >= mt->methods.size()) { return -1; } - if (mt->methods[k].time != p_time && p_exact) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(mt->methods[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && mt->methods[k].time != p_time)) { return -1; } return k; @@ -1543,7 +1543,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { if (k < 0 || k >= bt->values.size()) { return -1; } - if (bt->values[k].time != p_time && p_exact) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(bt->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && bt->values[k].time != p_time)) { return -1; } return k; @@ -1555,7 +1555,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { if (k < 0 || k >= at->values.size()) { return -1; } - if (at->values[k].time != p_time && p_exact) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(at->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && at->values[k].time != p_time)) { return -1; } return k; @@ -1567,7 +1567,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { if (k < 0 || k >= at->values.size()) { return -1; } - if (at->values[k].time != p_time && p_exact) { + if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(at->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && at->values[k].time != p_time)) { return -1; } return k; @@ -2944,12 +2944,12 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl // Not from_time > to_time but most recent of looping... if (p_looped_flag != Animation::LOOPED_FLAG_NONE) { if (!is_backward && Math::is_equal_approx(from_time, 0)) { - int edge = track_find_key(p_track, 0, true); + int edge = track_find_key(p_track, 0, FIND_MODE_EXACT); if (edge >= 0) { p_indices->push_back(edge); } } else if (is_backward && Math::is_equal_approx(to_time, length)) { - int edge = track_find_key(p_track, length, true); + int edge = track_find_key(p_track, length, FIND_MODE_EXACT); if (edge >= 0) { p_indices->push_back(edge); } @@ -2971,7 +2971,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl const PositionTrack *tt = static_cast<const PositionTrack *>(t); if (tt->compressed_track >= 0) { _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, from_time, p_indices); - _get_compressed_key_indices_in_range<3>(tt->compressed_track, CMP_EPSILON, to_time, p_indices); + _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, to_time, p_indices); } else { _track_get_key_indices_in_range(tt->positions, 0, from_time, p_indices, true); _track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices, false); @@ -2981,7 +2981,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl const RotationTrack *rt = static_cast<const RotationTrack *>(t); if (rt->compressed_track >= 0) { _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, from_time, p_indices); - _get_compressed_key_indices_in_range<3>(rt->compressed_track, CMP_EPSILON, to_time, p_indices); + _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, to_time, p_indices); } else { _track_get_key_indices_in_range(rt->rotations, 0, from_time, p_indices, true); _track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices, false); @@ -3072,7 +3072,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); if (bst->compressed_track >= 0) { _get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices); - _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length - CMP_EPSILON, p_indices); + _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length, p_indices); } else { _track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices, false); _track_get_key_indices_in_range(bst->blend_shapes, to_time, length, p_indices, true); @@ -3109,9 +3109,9 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl // The edge will be pingponged in the next frame and processed there, so let's ignore it now... if (!is_backward && Math::is_equal_approx(to_time, length)) { - to_time = length - CMP_EPSILON; + to_time -= CMP_EPSILON; } else if (is_backward && Math::is_equal_approx(from_time, 0)) { - from_time = CMP_EPSILON; + from_time += CMP_EPSILON; } } break; } @@ -3818,7 +3818,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_get_key_count", "track_idx"), &Animation::track_get_key_count); ClassDB::bind_method(D_METHOD("track_get_key_value", "track_idx", "key_idx"), &Animation::track_get_key_value); ClassDB::bind_method(D_METHOD("track_get_key_time", "track_idx", "key_idx"), &Animation::track_get_key_time); - ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "exact"), &Animation::track_find_key, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "find_mode"), &Animation::track_find_key, DEFVAL(FIND_MODE_NEAREST)); ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "track_idx", "interpolation"), &Animation::track_set_interpolation_type); ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "track_idx"), &Animation::track_get_interpolation_type); @@ -3905,6 +3905,10 @@ void Animation::_bind_methods() { BIND_ENUM_CONSTANT(LOOPED_FLAG_NONE); BIND_ENUM_CONSTANT(LOOPED_FLAG_END); BIND_ENUM_CONSTANT(LOOPED_FLAG_START); + + BIND_ENUM_CONSTANT(FIND_MODE_NEAREST); + BIND_ENUM_CONSTANT(FIND_MODE_APPROX); + BIND_ENUM_CONSTANT(FIND_MODE_EXACT); } void Animation::clear() { diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 0ac1279063..b7d5a683db 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -79,6 +79,12 @@ public: LOOPED_FLAG_START, }; + enum FindMode { + FIND_MODE_NEAREST, + FIND_MODE_APPROX, + FIND_MODE_EXACT, + }; + #ifdef TOOLS_ENABLED enum HandleMode { HANDLE_MODE_FREE, @@ -392,7 +398,7 @@ public: void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition); void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value); void track_set_key_time(int p_track, int p_key_idx, double p_time); - int track_find_key(int p_track, double p_time, bool p_exact = false) const; + int track_find_key(int p_track, double p_time, FindMode p_find_mode = FIND_MODE_NEAREST) const; void track_remove_key(int p_track, int p_idx); void track_remove_key_at_time(int p_track, double p_time); int track_get_key_count(int p_track) const; @@ -489,6 +495,7 @@ VARIANT_ENUM_CAST(Animation::InterpolationType); VARIANT_ENUM_CAST(Animation::UpdateMode); VARIANT_ENUM_CAST(Animation::LoopMode); VARIANT_ENUM_CAST(Animation::LoopedFlag); +VARIANT_ENUM_CAST(Animation::FindMode); #ifdef TOOLS_ENABLED VARIANT_ENUM_CAST(Animation::HandleMode); VARIANT_ENUM_CAST(Animation::HandleSetMode); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index f179b4b818..571ddee763 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -100,6 +100,11 @@ static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margi void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale) { scale = p_scale; + // Default theme properties. + theme->set_default_font(default_font); + theme->set_default_font_size(default_font_size * scale); + theme->set_default_base_scale(scale); + // Font colors const Color control_font_color = Color(0.875, 0.875, 0.875); const Color control_font_low_color = Color(0.7, 0.7, 0.7); diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index 7c78b757c7..858146da96 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -57,10 +57,18 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) { _set_item_shapes(idx, p_value); } else if (what == "preview") { set_item_preview(idx, p_value); - } else if (what == "navmesh") { - set_item_navmesh(idx, p_value); - } else if (what == "navmesh_transform") { - set_item_navmesh_transform(idx, p_value); + } else if (what == "navigation_mesh") { + set_item_navigation_mesh(idx, p_value); + } else if (what == "navigation_mesh_transform") { + set_item_navigation_mesh_transform(idx, p_value); +#ifndef DISABLE_DEPRECATED + } else if (what == "navmesh") { // Renamed in 4.0 beta 9. + set_item_navigation_mesh(idx, p_value); + } else if (what == "navmesh_transform") { // Renamed in 4.0 beta 9. + set_item_navigation_mesh_transform(idx, p_value); +#endif // DISABLE_DEPRECATED + } else if (what == "navigation_layers") { + set_item_navigation_layers(idx, p_value); } else { return false; } @@ -85,10 +93,18 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_item_mesh_transform(idx); } else if (what == "shapes") { r_ret = _get_item_shapes(idx); - } else if (what == "navmesh") { - r_ret = get_item_navmesh(idx); - } else if (what == "navmesh_transform") { - r_ret = get_item_navmesh_transform(idx); + } else if (what == "navigation_mesh") { + r_ret = get_item_navigation_mesh(idx); + } else if (what == "navigation_mesh_transform") { + r_ret = get_item_navigation_mesh_transform(idx); +#ifndef DISABLE_DEPRECATED + } else if (what == "navmesh") { // Renamed in 4.0 beta 9. + r_ret = get_item_navigation_mesh(idx); + } else if (what == "navmesh_transform") { // Renamed in 4.0 beta 9. + r_ret = get_item_navigation_mesh_transform(idx); +#endif // DISABLE_DEPRECATED + } else if (what == "navigation_layers") { + r_ret = get_item_navigation_layers(idx); } else if (what == "preview") { r_ret = get_item_preview(idx); } else { @@ -105,8 +121,9 @@ void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("mesh"), PROPERTY_HINT_RESOURCE_TYPE, "Mesh")); p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("mesh_transform"), PROPERTY_HINT_NONE, "suffix:m")); p_list->push_back(PropertyInfo(Variant::ARRAY, prop_name + PNAME("shapes"))); - p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("navmesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh")); - p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("navmesh_transform"), PROPERTY_HINT_NONE, "suffix:m")); + p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("navigation_mesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh")); + p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("navigation_mesh_transform"), PROPERTY_HINT_NONE, "suffix:m")); + p_list->push_back(PropertyInfo(Variant::INT, prop_name + PNAME("navigation_layers"), PROPERTY_HINT_LAYERS_3D_NAVIGATION)); p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("preview"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT)); } } @@ -150,18 +167,27 @@ void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) notify_property_list_changed(); } -void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh) { +void MeshLibrary::set_item_navigation_mesh(int p_item, const Ref<NavigationMesh> &p_navigation_mesh) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); - item_map[p_item].navmesh = p_navmesh; + item_map[p_item].navigation_mesh = p_navigation_mesh; notify_property_list_changed(); notify_change_to_owners(); emit_changed(); notify_property_list_changed(); } -void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform3D &p_transform) { +void MeshLibrary::set_item_navigation_mesh_transform(int p_item, const Transform3D &p_transform) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); - item_map[p_item].navmesh_transform = p_transform; + item_map[p_item].navigation_mesh_transform = p_transform; + notify_change_to_owners(); + emit_changed(); + notify_property_list_changed(); +} + +void MeshLibrary::set_item_navigation_layers(int p_item, uint32_t p_navigation_layers) { + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); + item_map[p_item].navigation_layers = p_navigation_layers; + notify_property_list_changed(); notify_change_to_owners(); emit_changed(); notify_property_list_changed(); @@ -194,14 +220,19 @@ Vector<MeshLibrary::ShapeData> MeshLibrary::get_item_shapes(int p_item) const { return item_map[p_item].shapes; } -Ref<NavigationMesh> MeshLibrary::get_item_navmesh(int p_item) const { +Ref<NavigationMesh> MeshLibrary::get_item_navigation_mesh(int p_item) const { ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<NavigationMesh>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); - return item_map[p_item].navmesh; + return item_map[p_item].navigation_mesh; } -Transform3D MeshLibrary::get_item_navmesh_transform(int p_item) const { +Transform3D MeshLibrary::get_item_navigation_mesh_transform(int p_item) const { ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform3D(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); - return item_map[p_item].navmesh_transform; + return item_map[p_item].navigation_mesh_transform; +} + +uint32_t MeshLibrary::get_item_navigation_layers(int p_item) const { + ERR_FAIL_COND_V_MSG(!item_map.has(p_item), 0, "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); + return item_map[p_item].navigation_layers; } Ref<Texture2D> MeshLibrary::get_item_preview(int p_item) const { @@ -314,15 +345,17 @@ void MeshLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name); ClassDB::bind_method(D_METHOD("set_item_mesh", "id", "mesh"), &MeshLibrary::set_item_mesh); ClassDB::bind_method(D_METHOD("set_item_mesh_transform", "id", "mesh_transform"), &MeshLibrary::set_item_mesh_transform); - ClassDB::bind_method(D_METHOD("set_item_navmesh", "id", "navmesh"), &MeshLibrary::set_item_navmesh); - ClassDB::bind_method(D_METHOD("set_item_navmesh_transform", "id", "navmesh"), &MeshLibrary::set_item_navmesh_transform); + ClassDB::bind_method(D_METHOD("set_item_navigation_mesh", "id", "navigation_mesh"), &MeshLibrary::set_item_navigation_mesh); + ClassDB::bind_method(D_METHOD("set_item_navigation_mesh_transform", "id", "navigation_mesh"), &MeshLibrary::set_item_navigation_mesh_transform); + ClassDB::bind_method(D_METHOD("set_item_navigation_layers", "id", "navigation_layers"), &MeshLibrary::set_item_navigation_layers); ClassDB::bind_method(D_METHOD("set_item_shapes", "id", "shapes"), &MeshLibrary::_set_item_shapes); ClassDB::bind_method(D_METHOD("set_item_preview", "id", "texture"), &MeshLibrary::set_item_preview); ClassDB::bind_method(D_METHOD("get_item_name", "id"), &MeshLibrary::get_item_name); ClassDB::bind_method(D_METHOD("get_item_mesh", "id"), &MeshLibrary::get_item_mesh); ClassDB::bind_method(D_METHOD("get_item_mesh_transform", "id"), &MeshLibrary::get_item_mesh_transform); - ClassDB::bind_method(D_METHOD("get_item_navmesh", "id"), &MeshLibrary::get_item_navmesh); - ClassDB::bind_method(D_METHOD("get_item_navmesh_transform", "id"), &MeshLibrary::get_item_navmesh_transform); + ClassDB::bind_method(D_METHOD("get_item_navigation_mesh", "id"), &MeshLibrary::get_item_navigation_mesh); + ClassDB::bind_method(D_METHOD("get_item_navigation_mesh_transform", "id"), &MeshLibrary::get_item_navigation_mesh_transform); + ClassDB::bind_method(D_METHOD("get_item_navigation_layers", "id"), &MeshLibrary::get_item_navigation_layers); ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes); ClassDB::bind_method(D_METHOD("get_item_preview", "id"), &MeshLibrary::get_item_preview); ClassDB::bind_method(D_METHOD("remove_item", "id"), &MeshLibrary::remove_item); diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index 79acb41c4e..1d5af9e176 100644 --- a/scene/resources/mesh_library.h +++ b/scene/resources/mesh_library.h @@ -49,11 +49,12 @@ public: struct Item { String name; Ref<Mesh> mesh; + Transform3D mesh_transform; Vector<ShapeData> shapes; Ref<Texture2D> preview; - Transform3D navmesh_transform; - Transform3D mesh_transform; - Ref<NavigationMesh> navmesh; + Ref<NavigationMesh> navigation_mesh; + Transform3D navigation_mesh_transform; + uint32_t navigation_layers = 1; }; RBMap<int, Item> item_map; @@ -74,15 +75,17 @@ public: void set_item_name(int p_item, const String &p_name); void set_item_mesh(int p_item, const Ref<Mesh> &p_mesh); void set_item_mesh_transform(int p_item, const Transform3D &p_transform); - void set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh); - void set_item_navmesh_transform(int p_item, const Transform3D &p_transform); + void set_item_navigation_mesh(int p_item, const Ref<NavigationMesh> &p_navigation_mesh); + void set_item_navigation_mesh_transform(int p_item, const Transform3D &p_transform); + void set_item_navigation_layers(int p_item, uint32_t p_navigation_layers); void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes); void set_item_preview(int p_item, const Ref<Texture2D> &p_preview); String get_item_name(int p_item) const; Ref<Mesh> get_item_mesh(int p_item) const; Transform3D get_item_mesh_transform(int p_item) const; - Ref<NavigationMesh> get_item_navmesh(int p_item) const; - Transform3D get_item_navmesh_transform(int p_item) const; + Ref<NavigationMesh> get_item_navigation_mesh(int p_item) const; + Transform3D get_item_navigation_mesh_transform(int p_item) const; + uint32_t get_item_navigation_layers(int p_item) const; Vector<ShapeData> get_item_shapes(int p_item) const; Ref<Texture2D> get_item_preview(int p_item) const; diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index de97498674..bf4291869f 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -225,13 +225,13 @@ float NavigationMesh::get_edge_max_error() const { return edge_max_error; } -void NavigationMesh::set_verts_per_poly(float p_value) { +void NavigationMesh::set_vertices_per_polygon(float p_value) { ERR_FAIL_COND(p_value < 3); - verts_per_poly = p_value; + vertices_per_polygon = p_value; } -float NavigationMesh::get_verts_per_poly() const { - return verts_per_poly; +float NavigationMesh::get_vertices_per_polygon() const { + return vertices_per_polygon; } void NavigationMesh::set_detail_sample_distance(float p_value) { @@ -483,8 +483,8 @@ void NavigationMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_edge_max_error", "edge_max_error"), &NavigationMesh::set_edge_max_error); ClassDB::bind_method(D_METHOD("get_edge_max_error"), &NavigationMesh::get_edge_max_error); - ClassDB::bind_method(D_METHOD("set_verts_per_poly", "verts_per_poly"), &NavigationMesh::set_verts_per_poly); - ClassDB::bind_method(D_METHOD("get_verts_per_poly"), &NavigationMesh::get_verts_per_poly); + ClassDB::bind_method(D_METHOD("set_vertices_per_polygon", "vertices_per_polygon"), &NavigationMesh::set_vertices_per_polygon); + ClassDB::bind_method(D_METHOD("get_vertices_per_polygon"), &NavigationMesh::get_vertices_per_polygon); ClassDB::bind_method(D_METHOD("set_detail_sample_distance", "detail_sample_dist"), &NavigationMesh::set_detail_sample_distance); ClassDB::bind_method(D_METHOD("get_detail_sample_distance"), &NavigationMesh::get_detail_sample_distance); @@ -527,9 +527,9 @@ void NavigationMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_PROPERTY_DEFAULT("geometry_collision_mask", 0xFFFFFFFF); - ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children,Group With Children,Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "Root Node Children,Group With Children,Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry_source_group_name"), "set_source_group_name", "get_source_group_name"); - ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navmesh")); + ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navigation_mesh_source_group")); ADD_GROUP("Cells", "cell_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_size", "get_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_height", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_height", "get_cell_height"); @@ -544,8 +544,8 @@ void NavigationMesh::_bind_methods() { ADD_GROUP("Edges", "edge_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater,suffix:m"), "set_edge_max_length", "get_edge_max_length"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater,suffix:m"), "set_edge_max_error", "get_edge_max_error"); - ADD_GROUP("Polygons", "polygon_"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "polygon_verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly"); + ADD_GROUP("Polygons", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vertices_per_polygon", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_vertices_per_polygon", "get_vertices_per_polygon"); ADD_GROUP("Details", "detail_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_distance", PROPERTY_HINT_RANGE, "0.1,16.0,0.01,or_greater,suffix:m"), "set_detail_sample_distance", "get_detail_sample_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:m"), "set_detail_sample_max_error", "get_detail_sample_max_error"); @@ -566,7 +566,7 @@ void NavigationMesh::_bind_methods() { BIND_ENUM_CONSTANT(PARSED_GEOMETRY_BOTH); BIND_ENUM_CONSTANT(PARSED_GEOMETRY_MAX); - BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_NAVMESH_CHILDREN); + BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_ROOT_NODE_CHILDREN); BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN); BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_GROUPS_EXPLICIT); BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_MAX); @@ -581,7 +581,7 @@ void NavigationMesh::_validate_property(PropertyInfo &p_property) const { } if (p_property.name == "geometry_source_group_name") { - if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) { + if (source_geometry_mode == SOURCE_GEOMETRY_ROOT_NODE_CHILDREN) { p_property.usage = PROPERTY_USAGE_NONE; return; } @@ -590,35 +590,16 @@ void NavigationMesh::_validate_property(PropertyInfo &p_property) const { #ifndef DISABLE_DEPRECATED bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) { - String prop_name = p_name; - if (prop_name.find("/") != -1) { - // Compatibility with pre-3.5 "category/path" property names. - prop_name = prop_name.replace("/", "_"); - if (prop_name == "sample_partition_type_sample_partition_type") { - set("sample_partition_type", p_value); - } else if (prop_name == "filter_filter_walkable_low_height_spans") { - set("filter_walkable_low_height_spans", p_value); - } else { - set(prop_name, p_value); - } - + if (p_name == "polygon_verts_per_poly") { // Renamed in 4.0 beta 9. + set_vertices_per_polygon(p_value); return true; } return false; } bool NavigationMesh::_get(const StringName &p_name, Variant &r_ret) const { - String prop_name = p_name; - if (prop_name.find("/") != -1) { - // Compatibility with pre-3.5 "category/path" property names. - prop_name = prop_name.replace("/", "_"); - if (prop_name == "sample_partition_type_sample_partition_type") { - r_ret = get("sample_partition_type"); - } else if (prop_name == "filter_filter_walkable_low_height_spans") { - r_ret = get("filter_walkable_low_height_spans"); - } else { - r_ret = get(prop_name); - } + if (p_name == "polygon_verts_per_poly") { // Renamed in 4.0 beta 9. + r_ret = get_vertices_per_polygon(); return true; } return false; diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index 5ddbd75dcb..3d072423db 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -84,7 +84,7 @@ public: }; enum SourceGeometryMode { - SOURCE_GEOMETRY_NAVMESH_CHILDREN = 0, + SOURCE_GEOMETRY_ROOT_NODE_CHILDREN = 0, SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN, SOURCE_GEOMETRY_GROUPS_EXPLICIT, SOURCE_GEOMETRY_MAX @@ -101,7 +101,7 @@ protected: float region_merge_size = 20.0f; float edge_max_length = 12.0f; float edge_max_error = 1.3f; - float verts_per_poly = 6.0f; + float vertices_per_polygon = 6.0f; float detail_sample_distance = 6.0f; float detail_sample_max_error = 1.0f; @@ -109,8 +109,8 @@ protected: ParsedGeometryType parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES; uint32_t collision_mask = 0xFFFFFFFF; - SourceGeometryMode source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN; - StringName source_group_name = "navmesh"; + SourceGeometryMode source_geometry_mode = SOURCE_GEOMETRY_ROOT_NODE_CHILDREN; + StringName source_group_name = "navigation_mesh_source_group"; bool filter_low_hanging_obstacles = false; bool filter_ledge_spans = false; @@ -168,8 +168,8 @@ public: void set_edge_max_error(float p_value); float get_edge_max_error() const; - void set_verts_per_poly(float p_value); - float get_verts_per_poly() const; + void set_vertices_per_polygon(float p_value); + float get_vertices_per_polygon() const; void set_detail_sample_distance(float p_value); float get_detail_sample_distance() const; diff --git a/scene/resources/navigation_polygon.cpp b/scene/resources/navigation_polygon.cpp new file mode 100644 index 0000000000..04077e95a7 --- /dev/null +++ b/scene/resources/navigation_polygon.cpp @@ -0,0 +1,354 @@ +/*************************************************************************/ +/* navigation_polygon.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "navigation_polygon.h" + +#include "core/core_string_names.h" +#include "core/math/geometry_2d.h" +#include "core/os/mutex.h" + +#include "thirdparty/misc/polypartition.h" + +#ifdef TOOLS_ENABLED +Rect2 NavigationPolygon::_edit_get_rect() const { + if (rect_cache_dirty) { + item_rect = Rect2(); + bool first = true; + + for (int i = 0; i < outlines.size(); i++) { + const Vector<Vector2> &outline = outlines[i]; + const int outline_size = outline.size(); + if (outline_size < 3) { + continue; + } + const Vector2 *p = outline.ptr(); + for (int j = 0; j < outline_size; j++) { + if (first) { + item_rect = Rect2(p[j], Vector2(0, 0)); + first = false; + } else { + item_rect.expand_to(p[j]); + } + } + } + + rect_cache_dirty = false; + } + return item_rect; +} + +bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + for (int i = 0; i < outlines.size(); i++) { + const Vector<Vector2> &outline = outlines[i]; + const int outline_size = outline.size(); + if (outline_size < 3) { + continue; + } + if (Geometry2D::is_point_in_polygon(p_point, Variant(outline))) { + return true; + } + } + return false; +} +#endif + +void NavigationPolygon::set_vertices(const Vector<Vector2> &p_vertices) { + { + MutexLock lock(navigation_mesh_generation); + navigation_mesh.unref(); + } + vertices = p_vertices; + rect_cache_dirty = true; +} + +Vector<Vector2> NavigationPolygon::get_vertices() const { + return vertices; +} + +void NavigationPolygon::_set_polygons(const TypedArray<Vector<int32_t>> &p_array) { + { + MutexLock lock(navigation_mesh_generation); + navigation_mesh.unref(); + } + polygons.resize(p_array.size()); + for (int i = 0; i < p_array.size(); i++) { + polygons.write[i].indices = p_array[i]; + } +} + +TypedArray<Vector<int32_t>> NavigationPolygon::_get_polygons() const { + TypedArray<Vector<int32_t>> ret; + ret.resize(polygons.size()); + for (int i = 0; i < ret.size(); i++) { + ret[i] = polygons[i].indices; + } + + return ret; +} + +void NavigationPolygon::_set_outlines(const TypedArray<Vector<Vector2>> &p_array) { + outlines.resize(p_array.size()); + for (int i = 0; i < p_array.size(); i++) { + outlines.write[i] = p_array[i]; + } + rect_cache_dirty = true; +} + +TypedArray<Vector<Vector2>> NavigationPolygon::_get_outlines() const { + TypedArray<Vector<Vector2>> ret; + ret.resize(outlines.size()); + for (int i = 0; i < ret.size(); i++) { + ret[i] = outlines[i]; + } + + return ret; +} + +void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) { + Polygon polygon; + polygon.indices = p_polygon; + polygons.push_back(polygon); + { + MutexLock lock(navigation_mesh_generation); + navigation_mesh.unref(); + } +} + +void NavigationPolygon::add_outline_at_index(const Vector<Vector2> &p_outline, int p_index) { + outlines.insert(p_index, p_outline); + rect_cache_dirty = true; +} + +int NavigationPolygon::get_polygon_count() const { + return polygons.size(); +} + +Vector<int> NavigationPolygon::get_polygon(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, polygons.size(), Vector<int>()); + return polygons[p_idx].indices; +} + +void NavigationPolygon::clear_polygons() { + polygons.clear(); + { + MutexLock lock(navigation_mesh_generation); + navigation_mesh.unref(); + } +} + +Ref<NavigationMesh> NavigationPolygon::get_navigation_mesh() { + MutexLock lock(navigation_mesh_generation); + + if (navigation_mesh.is_null()) { + navigation_mesh.instantiate(); + Vector<Vector3> verts; + { + verts.resize(get_vertices().size()); + Vector3 *w = verts.ptrw(); + + const Vector2 *r = get_vertices().ptr(); + + for (int i(0); i < get_vertices().size(); i++) { + w[i] = Vector3(r[i].x, 0.0, r[i].y); + } + } + navigation_mesh->set_vertices(verts); + + for (int i(0); i < get_polygon_count(); i++) { + navigation_mesh->add_polygon(get_polygon(i)); + } + } + + return navigation_mesh; +} + +void NavigationPolygon::add_outline(const Vector<Vector2> &p_outline) { + outlines.push_back(p_outline); + rect_cache_dirty = true; +} + +int NavigationPolygon::get_outline_count() const { + return outlines.size(); +} + +void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) { + ERR_FAIL_INDEX(p_idx, outlines.size()); + outlines.write[p_idx] = p_outline; + rect_cache_dirty = true; +} + +void NavigationPolygon::remove_outline(int p_idx) { + ERR_FAIL_INDEX(p_idx, outlines.size()); + outlines.remove_at(p_idx); + rect_cache_dirty = true; +} + +Vector<Vector2> NavigationPolygon::get_outline(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, outlines.size(), Vector<Vector2>()); + return outlines[p_idx]; +} + +void NavigationPolygon::clear_outlines() { + outlines.clear(); + rect_cache_dirty = true; +} + +void NavigationPolygon::make_polygons_from_outlines() { + { + MutexLock lock(navigation_mesh_generation); + navigation_mesh.unref(); + } + List<TPPLPoly> in_poly, out_poly; + + Vector2 outside_point(-1e10, -1e10); + + for (int i = 0; i < outlines.size(); i++) { + Vector<Vector2> ol = outlines[i]; + int olsize = ol.size(); + if (olsize < 3) { + continue; + } + const Vector2 *r = ol.ptr(); + for (int j = 0; j < olsize; j++) { + outside_point.x = MAX(r[j].x, outside_point.x); + outside_point.y = MAX(r[j].y, outside_point.y); + } + } + + outside_point += Vector2(0.7239784, 0.819238); //avoid precision issues + + for (int i = 0; i < outlines.size(); i++) { + Vector<Vector2> ol = outlines[i]; + int olsize = ol.size(); + if (olsize < 3) { + continue; + } + const Vector2 *r = ol.ptr(); + + int interscount = 0; + //test if this is an outer outline + for (int k = 0; k < outlines.size(); k++) { + if (i == k) { + continue; //no self intersect + } + + Vector<Vector2> ol2 = outlines[k]; + int olsize2 = ol2.size(); + if (olsize2 < 3) { + continue; + } + const Vector2 *r2 = ol2.ptr(); + + for (int l = 0; l < olsize2; l++) { + if (Geometry2D::segment_intersects_segment(r[0], outside_point, r2[l], r2[(l + 1) % olsize2], nullptr)) { + interscount++; + } + } + } + + bool outer = (interscount % 2) == 0; + + TPPLPoly tp; + tp.Init(olsize); + for (int j = 0; j < olsize; j++) { + tp[j] = r[j]; + } + + if (outer) { + tp.SetOrientation(TPPL_ORIENTATION_CCW); + } else { + tp.SetOrientation(TPPL_ORIENTATION_CW); + tp.SetHole(true); + } + + in_poly.push_back(tp); + } + + TPPLPartition tpart; + if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed! + ERR_PRINT("NavigationPolygon: Convex partition failed! Failed to convert outlines to a valid NavigationMesh." + "\nNavigationPolygon outlines can not overlap vertices or edges inside same outline or with other outlines or have any intersections." + "\nAdd the outmost and largest outline first. To add holes inside this outline add the smaller outlines with opposite winding order."); + return; + } + + polygons.clear(); + vertices.clear(); + + HashMap<Vector2, int> points; + for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) { + TPPLPoly &tp = I->get(); + + struct Polygon p; + + for (int64_t i = 0; i < tp.GetNumPoints(); i++) { + HashMap<Vector2, int>::Iterator E = points.find(tp[i]); + if (!E) { + E = points.insert(tp[i], vertices.size()); + vertices.push_back(tp[i]); + } + p.indices.push_back(E->value); + } + + polygons.push_back(p); + } + + emit_signal(CoreStringNames::get_singleton()->changed); +} + +void NavigationPolygon::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices); + ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices); + + ClassDB::bind_method(D_METHOD("add_polygon", "polygon"), &NavigationPolygon::add_polygon); + ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count); + ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon); + ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons); + ClassDB::bind_method(D_METHOD("get_navigation_mesh"), &NavigationPolygon::get_navigation_mesh); + + ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline); + ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index); + ClassDB::bind_method(D_METHOD("get_outline_count"), &NavigationPolygon::get_outline_count); + ClassDB::bind_method(D_METHOD("set_outline", "idx", "outline"), &NavigationPolygon::set_outline); + ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline); + ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline); + ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines); + ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines); + + ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons); + ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons); + + ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines); + ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines); + + ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines"); +} diff --git a/scene/resources/navigation_polygon.h b/scene/resources/navigation_polygon.h new file mode 100644 index 0000000000..e943cff04e --- /dev/null +++ b/scene/resources/navigation_polygon.h @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* navigation_polygon.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef NAVIGATION_POLYGON_H +#define NAVIGATION_POLYGON_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/navigation_mesh.h" + +class NavigationPolygon : public Resource { + GDCLASS(NavigationPolygon, Resource); + + Vector<Vector2> vertices; + struct Polygon { + Vector<int> indices; + }; + Vector<Polygon> polygons; + Vector<Vector<Vector2>> outlines; + + mutable Rect2 item_rect; + mutable bool rect_cache_dirty = true; + + Mutex navigation_mesh_generation; + // Navigation mesh + Ref<NavigationMesh> navigation_mesh; + +protected: + static void _bind_methods(); + + void _set_polygons(const TypedArray<Vector<int32_t>> &p_array); + TypedArray<Vector<int32_t>> _get_polygons() const; + + void _set_outlines(const TypedArray<Vector<Vector2>> &p_array); + TypedArray<Vector<Vector2>> _get_outlines() const; + +public: +#ifdef TOOLS_ENABLED + Rect2 _edit_get_rect() const; + bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const; +#endif + + void set_vertices(const Vector<Vector2> &p_vertices); + Vector<Vector2> get_vertices() const; + + void add_polygon(const Vector<int> &p_polygon); + int get_polygon_count() const; + + void add_outline(const Vector<Vector2> &p_outline); + void add_outline_at_index(const Vector<Vector2> &p_outline, int p_index); + void set_outline(int p_idx, const Vector<Vector2> &p_outline); + Vector<Vector2> get_outline(int p_idx) const; + void remove_outline(int p_idx); + int get_outline_count() const; + + void clear_outlines(); + void make_polygons_from_outlines(); + + Vector<int> get_polygon(int p_idx); + void clear_polygons(); + + Ref<NavigationMesh> get_navigation_mesh(); + + NavigationPolygon() {} + ~NavigationPolygon() {} +}; + +#endif // NAVIGATION_POLYGON_H diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 2e8fcb3717..54d3676c15 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -2171,6 +2171,24 @@ int TubeTrailMesh::get_section_rings() const { return section_rings; } +void TubeTrailMesh::set_cap_top(bool p_cap_top) { + cap_top = p_cap_top; + _request_update(); +} + +bool TubeTrailMesh::is_cap_top() const { + return cap_top; +} + +void TubeTrailMesh::set_cap_bottom(bool p_cap_bottom) { + cap_bottom = p_cap_bottom; + _request_update(); +} + +bool TubeTrailMesh::is_cap_bottom() const { + return cap_bottom; +} + void TubeTrailMesh::set_curve(const Ref<Curve> &p_curve) { if (curve == p_curve) { return; @@ -2284,49 +2302,21 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const { thisrow = point; } - // add top - float scale_pos = 1.0; - if (curve.is_valid() && curve->get_point_count() > 0) { - scale_pos = curve->sample_baked(0); - } - - if (scale_pos > CMP_EPSILON) { - float y = depth * 0.5; - - thisrow = point; - points.push_back(Vector3(0.0, y, 0)); - normals.push_back(Vector3(0.0, 1.0, 0.0)); - ADD_TANGENT(1.0, 0.0, 0.0, 1.0) - uvs.push_back(Vector2(0.25, 0.75)); - point++; - - bone_indices.push_back(0); - bone_indices.push_back(0); - bone_indices.push_back(0); - bone_indices.push_back(0); - - bone_weights.push_back(1.0); - bone_weights.push_back(0); - bone_weights.push_back(0); - bone_weights.push_back(0); - - float rm = radius * scale_pos; - - for (int i = 0; i <= radial_steps; i++) { - float r = i; - r /= radial_steps; - - float x = sin(r * Math_TAU); - float z = cos(r * Math_TAU); + if (cap_top) { + // add top + float scale_pos = 1.0; + if (curve.is_valid() && curve->get_point_count() > 0) { + scale_pos = curve->sample_baked(0); + } - float u = ((x + 1.0) * 0.25); - float v = 0.5 + ((z + 1.0) * 0.25); + if (scale_pos > CMP_EPSILON) { + float y = depth * 0.5; - Vector3 p = Vector3(x * rm, y, z * rm); - points.push_back(p); + thisrow = point; + points.push_back(Vector3(0.0, y, 0)); normals.push_back(Vector3(0.0, 1.0, 0.0)); ADD_TANGENT(1.0, 0.0, 0.0, 1.0) - uvs.push_back(Vector2(u, v)); + uvs.push_back(Vector2(0.25, 0.75)); point++; bone_indices.push_back(0); @@ -2339,57 +2329,59 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const { bone_weights.push_back(0); bone_weights.push_back(0); - if (i > 0) { - indices.push_back(thisrow); - indices.push_back(point - 1); - indices.push_back(point - 2); - } - } - } + float rm = radius * scale_pos; - float scale_neg = 1.0; - if (curve.is_valid() && curve->get_point_count() > 0) { - scale_neg = curve->sample_baked(1.0); - } + for (int i = 0; i <= radial_steps; i++) { + float r = i; + r /= radial_steps; - // add bottom - if (scale_neg > CMP_EPSILON) { - float y = depth * -0.5; + float x = sin(r * Math_TAU); + float z = cos(r * Math_TAU); - thisrow = point; - points.push_back(Vector3(0.0, y, 0.0)); - normals.push_back(Vector3(0.0, -1.0, 0.0)); - ADD_TANGENT(1.0, 0.0, 0.0, 1.0) - uvs.push_back(Vector2(0.75, 0.75)); - point++; + float u = ((x + 1.0) * 0.25); + float v = 0.5 + ((z + 1.0) * 0.25); - bone_indices.push_back(sections); - bone_indices.push_back(0); - bone_indices.push_back(0); - bone_indices.push_back(0); + Vector3 p = Vector3(x * rm, y, z * rm); + points.push_back(p); + normals.push_back(Vector3(0.0, 1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, 1.0) + uvs.push_back(Vector2(u, v)); + point++; - bone_weights.push_back(1.0); - bone_weights.push_back(0); - bone_weights.push_back(0); - bone_weights.push_back(0); + bone_indices.push_back(0); + bone_indices.push_back(0); + bone_indices.push_back(0); + bone_indices.push_back(0); - float rm = radius * scale_neg; + bone_weights.push_back(1.0); + bone_weights.push_back(0); + bone_weights.push_back(0); + bone_weights.push_back(0); - for (int i = 0; i <= radial_steps; i++) { - float r = i; - r /= radial_steps; + if (i > 0) { + indices.push_back(thisrow); + indices.push_back(point - 1); + indices.push_back(point - 2); + } + } + } + } - float x = sin(r * Math_TAU); - float z = cos(r * Math_TAU); + if (cap_bottom) { + float scale_neg = 1.0; + if (curve.is_valid() && curve->get_point_count() > 0) { + scale_neg = curve->sample_baked(1.0); + } - float u = 0.5 + ((x + 1.0) * 0.25); - float v = 1.0 - ((z + 1.0) * 0.25); + if (scale_neg > CMP_EPSILON) { + // add bottom + float y = depth * -0.5; - Vector3 p = Vector3(x * rm, y, z * rm); - points.push_back(p); + thisrow = point; + points.push_back(Vector3(0.0, y, 0.0)); normals.push_back(Vector3(0.0, -1.0, 0.0)); ADD_TANGENT(1.0, 0.0, 0.0, 1.0) - uvs.push_back(Vector2(u, v)); + uvs.push_back(Vector2(0.75, 0.75)); point++; bone_indices.push_back(sections); @@ -2402,10 +2394,40 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const { bone_weights.push_back(0); bone_weights.push_back(0); - if (i > 0) { - indices.push_back(thisrow); - indices.push_back(point - 2); - indices.push_back(point - 1); + float rm = radius * scale_neg; + + for (int i = 0; i <= radial_steps; i++) { + float r = i; + r /= radial_steps; + + float x = sin(r * Math_TAU); + float z = cos(r * Math_TAU); + + float u = 0.5 + ((x + 1.0) * 0.25); + float v = 1.0 - ((z + 1.0) * 0.25); + + Vector3 p = Vector3(x * rm, y, z * rm); + points.push_back(p); + normals.push_back(Vector3(0.0, -1.0, 0.0)); + ADD_TANGENT(1.0, 0.0, 0.0, 1.0) + uvs.push_back(Vector2(u, v)); + point++; + + bone_indices.push_back(sections); + bone_indices.push_back(0); + bone_indices.push_back(0); + bone_indices.push_back(0); + + bone_weights.push_back(1.0); + bone_weights.push_back(0); + bone_weights.push_back(0); + bone_weights.push_back(0); + + if (i > 0) { + indices.push_back(thisrow); + indices.push_back(point - 2); + indices.push_back(point - 1); + } } } } @@ -2435,6 +2457,12 @@ void TubeTrailMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_section_rings", "section_rings"), &TubeTrailMesh::set_section_rings); ClassDB::bind_method(D_METHOD("get_section_rings"), &TubeTrailMesh::get_section_rings); + ClassDB::bind_method(D_METHOD("set_cap_top", "cap_top"), &TubeTrailMesh::set_cap_top); + ClassDB::bind_method(D_METHOD("is_cap_top"), &TubeTrailMesh::is_cap_top); + + ClassDB::bind_method(D_METHOD("set_cap_bottom", "cap_bottom"), &TubeTrailMesh::set_cap_bottom); + ClassDB::bind_method(D_METHOD("is_cap_bottom"), &TubeTrailMesh::is_cap_bottom); + ClassDB::bind_method(D_METHOD("set_curve", "curve"), &TubeTrailMesh::set_curve); ClassDB::bind_method(D_METHOD("get_curve"), &TubeTrailMesh::get_curve); @@ -2447,13 +2475,16 @@ void TubeTrailMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "section_rings", PROPERTY_HINT_RANGE, "1,128,1"), "set_section_rings", "get_section_rings"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_top"), "set_cap_top", "is_cap_top"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cap_bottom"), "set_cap_bottom", "is_cap_bottom"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve"); } TubeTrailMesh::TubeTrailMesh() { } -// TUBE TRAIL +// RIBBON TRAIL void RibbonTrailMesh::set_shape(Shape p_shape) { shape = p_shape; diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 06f9781b84..5cef042a18 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -431,6 +431,8 @@ private: int sections = 5; float section_length = 0.2; int section_rings = 3; + bool cap_top = true; + bool cap_bottom = true; Ref<Curve> curve; @@ -456,6 +458,12 @@ public: void set_section_rings(const int p_section_rings); int get_section_rings() const; + void set_cap_top(bool p_cap_top); + bool is_cap_top() const; + + void set_cap_bottom(bool p_cap_bottom); + bool is_cap_bottom() const; + void set_curve(const Ref<Curve> &p_curve); Ref<Curve> get_curve() const; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 2106619a6b..18915e294e 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -1591,35 +1591,28 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, return false; } - Rect2 rc = region; - Rect2 src = p_src_rect; if (src.size == Size2()) { - src.size = rc.size; + src.size = region.size; } Vector2 scale = p_rect.size / src.size; - src.position += (rc.position - margin.position); - Rect2 src_c = rc.intersection(src); - if (src_c.size == Size2()) { + src.position += (region.position - margin.position); + Rect2 src_clipped = region.intersection(src); + if (src_clipped.size == Size2()) { return false; } - Vector2 ofs = (src_c.position - src.position); + Vector2 ofs = (src_clipped.position - src.position); if (scale.x < 0) { - float mx = (margin.size.width - margin.position.x); - mx -= margin.position.x; - ofs.x = -(ofs.x + mx); + ofs.x += (src_clipped.size.x - src.size.x); } if (scale.y < 0) { - float my = margin.size.height - margin.position.y; - my -= margin.position.y; - ofs.y = -(ofs.y + my); + ofs.y += (src_clipped.size.y - src.size.y); } - Rect2 dr(p_rect.position + ofs * scale, src_c.size * scale); - r_rect = dr; - r_src_rect = src_c; + r_rect = Rect2(p_rect.position + ofs * scale, src_clipped.size * scale); + r_src_rect = src_clipped; return true; } diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 9d2537bb4d..0b0461432b 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -35,7 +35,6 @@ #include "core/math/geometry_2d.h" #include "core/templates/local_vector.h" #include "core/templates/rb_set.h" -#include "scene/2d/navigation_region_2d.h" #include "scene/gui/control.h" #include "scene/resources/convex_polygon_shape_2d.h" #include "servers/navigation_server_2d.h" @@ -477,7 +476,7 @@ int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source int new_source_id = p_atlas_source_id_override >= 0 ? p_atlas_source_id_override : next_source_id; sources[new_source_id] = p_tile_set_source; - source_ids.append(new_source_id); + source_ids.push_back(new_source_id); source_ids.sort(); p_tile_set_source->set_tile_set(this); _compute_next_source_id(); @@ -517,7 +516,7 @@ void TileSet::set_source_id(int p_source_id, int p_new_source_id) { sources.erase(p_source_id); source_ids.erase(p_source_id); - source_ids.append(p_new_source_id); + source_ids.push_back(p_new_source_id); source_ids.sort(); _compute_next_source_id(); @@ -1297,7 +1296,7 @@ void TileSet::cleanup_invalid_tile_proxies() { Vector<int> source_to_remove; for (const KeyValue<int, int> &E : source_level_proxies) { if (has_source(E.key)) { - source_to_remove.append(E.key); + source_to_remove.push_back(E.key); } } for (int i = 0; i < source_to_remove.size(); i++) { @@ -1309,7 +1308,7 @@ void TileSet::cleanup_invalid_tile_proxies() { for (const KeyValue<Array, Array> &E : coords_level_proxies) { Array a = E.key; if (has_source(a[0]) && get_source(a[0])->has_tile(a[1])) { - coords_to_remove.append(a); + coords_to_remove.push_back(a); } } for (int i = 0; i < coords_to_remove.size(); i++) { @@ -1322,7 +1321,7 @@ void TileSet::cleanup_invalid_tile_proxies() { for (const KeyValue<Array, Array> &E : alternative_level_proxies) { Array a = E.key; if (has_source(a[0]) && get_source(a[0])->has_tile(a[1]) && get_source(a[0])->has_alternative_tile(a[1], a[2])) { - alternative_to_remove.append(a); + alternative_to_remove.push_back(a); } } for (int i = 0; i < alternative_to_remove.size(); i++) { @@ -1439,16 +1438,18 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti Vector<Vector2> TileSet::get_tile_shape_polygon() { Vector<Vector2> points; if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { - points.append(Vector2(-0.5, -0.5)); - points.append(Vector2(0.5, -0.5)); - points.append(Vector2(0.5, 0.5)); - points.append(Vector2(-0.5, 0.5)); + points.push_back(Vector2(-0.5, -0.5)); + points.push_back(Vector2(0.5, -0.5)); + points.push_back(Vector2(0.5, 0.5)); + points.push_back(Vector2(-0.5, 0.5)); + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + points.push_back(Vector2(0.0, -0.5)); + points.push_back(Vector2(-0.5, 0.0)); + points.push_back(Vector2(0.0, 0.5)); + points.push_back(Vector2(0.5, 0.0)); } else { float overlap = 0.0; switch (tile_shape) { - case TileSet::TILE_SHAPE_ISOMETRIC: - overlap = 0.5; - break; case TileSet::TILE_SHAPE_HEXAGON: overlap = 0.25; break; @@ -1459,12 +1460,13 @@ Vector<Vector2> TileSet::get_tile_shape_polygon() { break; } - points.append(Vector2(0.0, -0.5)); - points.append(Vector2(-0.5, overlap - 0.5)); - points.append(Vector2(-0.5, 0.5 - overlap)); - points.append(Vector2(0.0, 0.5)); - points.append(Vector2(0.5, 0.5 - overlap)); - points.append(Vector2(0.5, overlap - 0.5)); + points.push_back(Vector2(0.0, -0.5)); + points.push_back(Vector2(-0.5, overlap - 0.5)); + points.push_back(Vector2(-0.5, 0.5 - overlap)); + points.push_back(Vector2(0.0, 0.5)); + points.push_back(Vector2(0.5, 0.5 - overlap)); + points.push_back(Vector2(0.5, overlap - 0.5)); + if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) { for (int i = 0; i < points.size(); i++) { points.write[i] = Vector2(points[i].y, points[i].x); @@ -3854,7 +3856,7 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) tiles[coords].alternatives[alternative_id] = memnew(TileData); tiles[coords].alternatives[alternative_id]->set_tile_set(tile_set); tiles[coords].alternatives[alternative_id]->set_allow_transform(alternative_id > 0); - tiles[coords].alternatives_ids.append(alternative_id); + tiles[coords].alternatives_ids.push_back(alternative_id); } if (components.size() >= 3) { bool valid; @@ -4028,11 +4030,11 @@ void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector tad.alternatives[0]->set_allow_transform(false); tad.alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed)); tad.alternatives[0]->notify_property_list_changed(); - tad.alternatives_ids.append(0); + tad.alternatives_ids.push_back(0); // Create and resize the tile. tiles.insert(p_atlas_coords, tad); - tiles_ids.append(p_atlas_coords); + tiles_ids.push_back(p_atlas_coords); tiles_ids.sort(); _create_coords_mapping_cache(p_atlas_coords); @@ -4343,7 +4345,7 @@ void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_ tiles.erase(p_atlas_coords); tiles_ids.erase(p_atlas_coords); - tiles_ids.append(new_atlas_coords); + tiles_ids.push_back(new_atlas_coords); tiles_ids.sort(); } tiles[new_atlas_coords].size_in_atlas = new_size; @@ -4365,7 +4367,7 @@ int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, i tiles[p_atlas_coords].alternatives[new_alternative_id]->set_allow_transform(true); tiles[p_atlas_coords].alternatives[new_alternative_id]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed)); tiles[p_atlas_coords].alternatives[new_alternative_id]->notify_property_list_changed(); - tiles[p_atlas_coords].alternatives_ids.append(new_alternative_id); + tiles[p_atlas_coords].alternatives_ids.push_back(new_alternative_id); tiles[p_atlas_coords].alternatives_ids.sort(); _compute_next_alternative_id(p_atlas_coords); @@ -4395,7 +4397,7 @@ void TileSetAtlasSource::set_alternative_tile_id(const Vector2i p_atlas_coords, ERR_FAIL_COND_MSG(tiles[p_atlas_coords].alternatives.has(p_new_id), vformat("TileSetAtlasSource has already an alternative with id %d at %s.", p_new_id, String(p_atlas_coords))); tiles[p_atlas_coords].alternatives[p_new_id] = tiles[p_atlas_coords].alternatives[p_alternative_tile]; - tiles[p_atlas_coords].alternatives_ids.append(p_new_id); + tiles[p_atlas_coords].alternatives_ids.push_back(p_new_id); tiles[p_atlas_coords].alternatives.erase(p_alternative_tile); tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile); @@ -4683,7 +4685,7 @@ int TileSetScenesCollectionSource::create_scene_tile(Ref<PackedScene> p_packed_s int new_scene_id = p_id_override >= 0 ? p_id_override : next_scene_id; scenes[new_scene_id] = SceneData(); - scenes_ids.append(new_scene_id); + scenes_ids.push_back(new_scene_id); scenes_ids.sort(); set_scene_tile_scene(new_scene_id, p_packed_scene); _compute_next_alternative_id(); @@ -4700,7 +4702,7 @@ void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) { scenes[p_new_id] = SceneData(); scenes[p_new_id] = scenes[p_id]; - scenes_ids.append(p_new_id); + scenes_ids.push_back(p_new_id); scenes_ids.sort(); _compute_next_alternative_id(); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 9f465a17e9..88bbbd157a 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -36,10 +36,10 @@ #include "core/templates/local_vector.h" #include "core/templates/rb_set.h" #include "scene/2d/light_occluder_2d.h" -#include "scene/2d/navigation_region_2d.h" #include "scene/main/canvas_item.h" #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" +#include "scene/resources/navigation_polygon.h" #include "scene/resources/packed_scene.h" #include "scene/resources/physics_material.h" #include "scene/resources/shape_2d.h" diff --git a/scene/theme/theme_db.cpp b/scene/theme/theme_db.cpp index 0268a685fe..ae64313741 100644 --- a/scene/theme/theme_db.cpp +++ b/scene/theme/theme_db.cpp @@ -70,7 +70,9 @@ void ThemeDB::initialize_theme() { Ref<Font> font; if (!font_path.is_empty()) { font = ResourceLoader::load(font_path); - if (!font.is_valid()) { + if (font.is_valid()) { + set_fallback_font(font); + } else { ERR_PRINT("Error loading custom font '" + font_path + "'"); } } @@ -84,9 +86,6 @@ void ThemeDB::initialize_theme() { Ref<Theme> theme = ResourceLoader::load(theme_path); if (theme.is_valid()) { set_project_theme(theme); - if (font.is_valid()) { - set_fallback_font(font); - } } else { ERR_PRINT("Error loading custom theme '" + theme_path + "'"); } diff --git a/scene/theme/theme_owner.cpp b/scene/theme/theme_owner.cpp index e89aa1b28d..44e0c5d0c8 100644 --- a/scene/theme/theme_owner.cpp +++ b/scene/theme/theme_owner.cpp @@ -205,16 +205,7 @@ Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const S while (owner_node) { // For each theme resource check the theme types provided and see if p_name exists with any of them. for (const StringName &E : p_theme_types) { - Ref<Theme> owner_theme; - - Control *owner_c = Object::cast_to<Control>(owner_node); - if (owner_c) { - owner_theme = owner_c->get_theme(); - } - Window *owner_w = Object::cast_to<Window>(owner_node); - if (owner_w) { - owner_theme = owner_w->get_theme(); - } + Ref<Theme> owner_theme = _get_owner_node_theme(owner_node); if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) { return owner_theme->get_theme_item(p_data_type, p_name, E); @@ -254,16 +245,7 @@ bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const Stri while (owner_node) { // For each theme resource check the theme types provided and see if p_name exists with any of them. for (const StringName &E : p_theme_types) { - Ref<Theme> owner_theme; - - Control *owner_c = Object::cast_to<Control>(owner_node); - if (owner_c) { - owner_theme = owner_c->get_theme(); - } - Window *owner_w = Object::cast_to<Window>(owner_node); - if (owner_w) { - owner_theme = owner_w->get_theme(); - } + Ref<Theme> owner_theme = _get_owner_node_theme(owner_node); if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) { return true; @@ -299,16 +281,7 @@ float ThemeOwner::get_theme_default_base_scale() { Node *owner_node = get_owner_node(); while (owner_node) { - Ref<Theme> owner_theme; - - Control *owner_c = Object::cast_to<Control>(owner_node); - if (owner_c) { - owner_theme = owner_c->get_theme(); - } - Window *owner_w = Object::cast_to<Window>(owner_node); - if (owner_w) { - owner_theme = owner_w->get_theme(); - } + Ref<Theme> owner_theme = _get_owner_node_theme(owner_node); if (owner_theme.is_valid() && owner_theme->has_default_base_scale()) { return owner_theme->get_default_base_scale(); @@ -338,16 +311,7 @@ Ref<Font> ThemeOwner::get_theme_default_font() { Node *owner_node = get_owner_node(); while (owner_node) { - Ref<Theme> owner_theme; - - Control *owner_c = Object::cast_to<Control>(owner_node); - if (owner_c) { - owner_theme = owner_c->get_theme(); - } - Window *owner_w = Object::cast_to<Window>(owner_node); - if (owner_w) { - owner_theme = owner_w->get_theme(); - } + Ref<Theme> owner_theme = _get_owner_node_theme(owner_node); if (owner_theme.is_valid() && owner_theme->has_default_font()) { return owner_theme->get_default_font(); @@ -377,16 +341,7 @@ int ThemeOwner::get_theme_default_font_size() { Node *owner_node = get_owner_node(); while (owner_node) { - Ref<Theme> owner_theme; - - Control *owner_c = Object::cast_to<Control>(owner_node); - if (owner_c) { - owner_theme = owner_c->get_theme(); - } - Window *owner_w = Object::cast_to<Window>(owner_node); - if (owner_w) { - owner_theme = owner_w->get_theme(); - } + Ref<Theme> owner_theme = _get_owner_node_theme(owner_node); if (owner_theme.is_valid() && owner_theme->has_default_font_size()) { return owner_theme->get_default_font_size(); @@ -408,3 +363,17 @@ int ThemeOwner::get_theme_default_font_size() { } return ThemeDB::get_singleton()->get_fallback_font_size(); } + +Ref<Theme> ThemeOwner::_get_owner_node_theme(Node *p_owner_node) const { + const Control *owner_c = Object::cast_to<Control>(p_owner_node); + if (owner_c) { + return owner_c->get_theme(); + } + + const Window *owner_w = Object::cast_to<Window>(p_owner_node); + if (owner_w) { + return owner_w->get_theme(); + } + + return Ref<Theme>(); +} diff --git a/scene/theme/theme_owner.h b/scene/theme/theme_owner.h index 59b72c1627..60d60f525c 100644 --- a/scene/theme/theme_owner.h +++ b/scene/theme/theme_owner.h @@ -43,6 +43,7 @@ class ThemeOwner : public Object { Window *owner_window = nullptr; Node *_get_next_owner_node(Node *p_from_node) const; + Ref<Theme> _get_owner_node_theme(Node *p_owner_node) const; public: // Theme owner node. diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 113e728106..84c21f7cd6 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -410,12 +410,12 @@ AudioStreamPlaybackMicrophone::AudioStreamPlaybackMicrophone() { //////////////////////////////// -void AudioStreamRandomizer::add_stream(int p_index) { +void AudioStreamRandomizer::add_stream(int p_index, Ref<AudioStream> p_stream, float p_weight) { if (p_index < 0) { p_index = audio_stream_pool.size(); } ERR_FAIL_COND(p_index > audio_stream_pool.size()); - PoolEntry entry{ nullptr, 1.0f }; + PoolEntry entry{ p_stream, p_weight }; audio_stream_pool.insert(p_index, entry); emit_signal(SNAME("changed")); notify_property_list_changed(); @@ -709,7 +709,7 @@ void AudioStreamRandomizer::_get_property_list(List<PropertyInfo> *p_list) const } void AudioStreamRandomizer::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_stream", "index"), &AudioStreamRandomizer::add_stream); + ClassDB::bind_method(D_METHOD("add_stream", "index", "stream", "weight"), &AudioStreamRandomizer::add_stream, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("move_stream", "index_from", "index_to"), &AudioStreamRandomizer::move_stream); ClassDB::bind_method(D_METHOD("remove_stream", "index"), &AudioStreamRandomizer::remove_stream); diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index c6ae6817e7..0d3f7bca04 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -241,7 +241,7 @@ protected: void _get_property_list(List<PropertyInfo> *p_list) const; public: - void add_stream(int p_index); + void add_stream(int p_index, Ref<AudioStream> p_stream, float p_weight = 1.0); void move_stream(int p_index_from, int p_index_to); void remove_stream(int p_index); diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index e657570f9b..c7d626c159 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -449,12 +449,8 @@ void AudioServer::_mix_step() { case AudioStreamPlaybackListNode::AWAITING_DELETION: case AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION: playback_list.erase(playback, [](AudioStreamPlaybackListNode *p) { - if (p->prev_bus_details) { - delete p->prev_bus_details; - } - if (p->bus_details) { - delete p->bus_details; - } + delete p->prev_bus_details; + delete p->bus_details; p->stream_playback.unref(); delete p; }); diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp index 811ff231fc..4ed2bb49d4 100644 --- a/servers/extensions/physics_server_3d_extension.cpp +++ b/servers/extensions/physics_server_3d_extension.cpp @@ -400,6 +400,9 @@ void PhysicsServer3DExtension::_bind_methods() { GDVIRTUAL_BIND(_joint_set_solver_priority, "joint", "priority"); GDVIRTUAL_BIND(_joint_get_solver_priority, "joint"); + GDVIRTUAL_BIND(_joint_disable_collisions_between_bodies, "joint", "disable"); + GDVIRTUAL_BIND(_joint_is_disabled_collisions_between_bodies, "joint"); + GDVIRTUAL_BIND(_free_rid, "rid"); GDVIRTUAL_BIND(_set_active, "active"); diff --git a/servers/navigation/navigation_path_query_parameters_2d.cpp b/servers/navigation/navigation_path_query_parameters_2d.cpp index 574af90be1..717ada3834 100644 --- a/servers/navigation/navigation_path_query_parameters_2d.cpp +++ b/servers/navigation/navigation_path_query_parameters_2d.cpp @@ -105,11 +105,19 @@ Vector2 NavigationPathQueryParameters2D::get_target_position() const { void NavigationPathQueryParameters2D::set_navigation_layers(uint32_t p_navigation_layers) { parameters.navigation_layers = p_navigation_layers; -}; +} uint32_t NavigationPathQueryParameters2D::get_navigation_layers() const { return parameters.navigation_layers; -}; +} + +void NavigationPathQueryParameters2D::set_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_flags) { + parameters.metadata_flags = (int64_t)p_flags; +} + +BitField<NavigationPathQueryParameters2D::PathMetadataFlags> NavigationPathQueryParameters2D::get_metadata_flags() const { + return (int64_t)parameters.metadata_flags; +} void NavigationPathQueryParameters2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationPathQueryParameters2D::set_pathfinding_algorithm); @@ -130,15 +138,25 @@ void NavigationPathQueryParameters2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationPathQueryParameters2D::set_navigation_layers); ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationPathQueryParameters2D::get_navigation_layers); + ClassDB::bind_method(D_METHOD("set_metadata_flags", "flags"), &NavigationPathQueryParameters2D::set_metadata_flags); + ClassDB::bind_method(D_METHOD("get_metadata_flags"), &NavigationPathQueryParameters2D::get_metadata_flags); + ADD_PROPERTY(PropertyInfo(Variant::RID, "map"), "set_map", "get_map"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "start_position"), "set_start_position", "get_start_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position"), "set_target_position", "get_target_position"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_metadata_flags", "get_metadata_flags"); BIND_ENUM_CONSTANT(PATHFINDING_ALGORITHM_ASTAR); BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_CORRIDORFUNNEL); BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_EDGECENTERED); + + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_NONE); + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_TYPES); + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_RIDS); + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_OWNERS); + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_ALL); } diff --git a/servers/navigation/navigation_path_query_parameters_2d.h b/servers/navigation/navigation_path_query_parameters_2d.h index c0ef337a27..aeabe1f690 100644 --- a/servers/navigation/navigation_path_query_parameters_2d.h +++ b/servers/navigation/navigation_path_query_parameters_2d.h @@ -52,6 +52,14 @@ public: PATH_POSTPROCESSING_EDGECENTERED, }; + enum PathMetadataFlags { + PATH_METADATA_INCLUDE_NONE = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_NONE, + PATH_METADATA_INCLUDE_TYPES = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_TYPES, + PATH_METADATA_INCLUDE_RIDS = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_RIDS, + PATH_METADATA_INCLUDE_OWNERS = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_OWNERS, + PATH_METADATA_INCLUDE_ALL = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_ALL + }; + const NavigationUtilities::PathQueryParameters &get_parameters() const { return parameters; } void set_pathfinding_algorithm(const PathfindingAlgorithm p_pathfinding_algorithm); @@ -71,9 +79,13 @@ public: void set_navigation_layers(uint32_t p_navigation_layers); uint32_t get_navigation_layers() const; + + void set_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_flags); + BitField<NavigationPathQueryParameters2D::PathMetadataFlags> get_metadata_flags() const; }; VARIANT_ENUM_CAST(NavigationPathQueryParameters2D::PathfindingAlgorithm); VARIANT_ENUM_CAST(NavigationPathQueryParameters2D::PathPostProcessing); +VARIANT_BITFIELD_CAST(NavigationPathQueryParameters2D::PathMetadataFlags); #endif // NAVIGATION_PATH_QUERY_PARAMETERS_2D_H diff --git a/servers/navigation/navigation_path_query_parameters_3d.cpp b/servers/navigation/navigation_path_query_parameters_3d.cpp index b09448e82e..180af57af5 100644 --- a/servers/navigation/navigation_path_query_parameters_3d.cpp +++ b/servers/navigation/navigation_path_query_parameters_3d.cpp @@ -111,6 +111,14 @@ uint32_t NavigationPathQueryParameters3D::get_navigation_layers() const { return parameters.navigation_layers; } +void NavigationPathQueryParameters3D::set_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_flags) { + parameters.metadata_flags = (int64_t)p_flags; +} + +BitField<NavigationPathQueryParameters3D::PathMetadataFlags> NavigationPathQueryParameters3D::get_metadata_flags() const { + return (int64_t)parameters.metadata_flags; +} + void NavigationPathQueryParameters3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationPathQueryParameters3D::set_pathfinding_algorithm); ClassDB::bind_method(D_METHOD("get_pathfinding_algorithm"), &NavigationPathQueryParameters3D::get_pathfinding_algorithm); @@ -130,15 +138,25 @@ void NavigationPathQueryParameters3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationPathQueryParameters3D::set_navigation_layers); ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationPathQueryParameters3D::get_navigation_layers); + ClassDB::bind_method(D_METHOD("set_metadata_flags", "flags"), &NavigationPathQueryParameters3D::set_metadata_flags); + ClassDB::bind_method(D_METHOD("get_metadata_flags"), &NavigationPathQueryParameters3D::get_metadata_flags); + ADD_PROPERTY(PropertyInfo(Variant::RID, "map"), "set_map", "get_map"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "start_position"), "set_start_position", "get_start_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_metadata_flags", "get_metadata_flags"); BIND_ENUM_CONSTANT(PATHFINDING_ALGORITHM_ASTAR); BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_CORRIDORFUNNEL); BIND_ENUM_CONSTANT(PATH_POSTPROCESSING_EDGECENTERED); + + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_NONE); + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_TYPES); + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_RIDS); + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_OWNERS); + BIND_BITFIELD_FLAG(PATH_METADATA_INCLUDE_ALL); } diff --git a/servers/navigation/navigation_path_query_parameters_3d.h b/servers/navigation/navigation_path_query_parameters_3d.h index b4cf02fc79..386c83dece 100644 --- a/servers/navigation/navigation_path_query_parameters_3d.h +++ b/servers/navigation/navigation_path_query_parameters_3d.h @@ -52,6 +52,14 @@ public: PATH_POSTPROCESSING_EDGECENTERED, }; + enum PathMetadataFlags { + PATH_METADATA_INCLUDE_NONE = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_NONE, + PATH_METADATA_INCLUDE_TYPES = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_TYPES, + PATH_METADATA_INCLUDE_RIDS = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_RIDS, + PATH_METADATA_INCLUDE_OWNERS = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_OWNERS, + PATH_METADATA_INCLUDE_ALL = NavigationUtilities::PathMetadataFlags::PATH_INCLUDE_ALL + }; + const NavigationUtilities::PathQueryParameters &get_parameters() const { return parameters; } void set_pathfinding_algorithm(const PathfindingAlgorithm p_pathfinding_algorithm); @@ -71,9 +79,13 @@ public: void set_navigation_layers(uint32_t p_navigation_layers); uint32_t get_navigation_layers() const; + + void set_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_flags); + BitField<NavigationPathQueryParameters3D::PathMetadataFlags> get_metadata_flags() const; }; VARIANT_ENUM_CAST(NavigationPathQueryParameters3D::PathfindingAlgorithm); VARIANT_ENUM_CAST(NavigationPathQueryParameters3D::PathPostProcessing); +VARIANT_BITFIELD_CAST(NavigationPathQueryParameters3D::PathMetadataFlags); #endif // NAVIGATION_PATH_QUERY_PARAMETERS_3D_H diff --git a/servers/navigation/navigation_path_query_result_2d.cpp b/servers/navigation/navigation_path_query_result_2d.cpp index 8a55451e40..e2764daa9a 100644 --- a/servers/navigation/navigation_path_query_result_2d.cpp +++ b/servers/navigation/navigation_path_query_result_2d.cpp @@ -38,15 +38,57 @@ const Vector<Vector2> &NavigationPathQueryResult2D::get_path() const { return path; } +void NavigationPathQueryResult2D::set_path_types(const Vector<int32_t> &p_path_types) { + path_types = p_path_types; +} + +const Vector<int32_t> &NavigationPathQueryResult2D::get_path_types() const { + return path_types; +} + +void NavigationPathQueryResult2D::set_path_rids(const TypedArray<RID> &p_path_rids) { + path_rids = p_path_rids; +} + +TypedArray<RID> NavigationPathQueryResult2D::get_path_rids() const { + return path_rids; +} + +void NavigationPathQueryResult2D::set_path_owner_ids(const Vector<int64_t> &p_path_owner_ids) { + path_owner_ids = p_path_owner_ids; +} + +const Vector<int64_t> &NavigationPathQueryResult2D::get_path_owner_ids() const { + return path_owner_ids; +} + void NavigationPathQueryResult2D::reset() { path.clear(); + path_types.clear(); + path_rids.clear(); + path_owner_ids.clear(); } void NavigationPathQueryResult2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_path", "path"), &NavigationPathQueryResult2D::set_path); ClassDB::bind_method(D_METHOD("get_path"), &NavigationPathQueryResult2D::get_path); + ClassDB::bind_method(D_METHOD("set_path_types", "path_types"), &NavigationPathQueryResult2D::set_path_types); + ClassDB::bind_method(D_METHOD("get_path_types"), &NavigationPathQueryResult2D::get_path_types); + + ClassDB::bind_method(D_METHOD("set_path_rids", "path_rids"), &NavigationPathQueryResult2D::set_path_rids); + ClassDB::bind_method(D_METHOD("get_path_rids"), &NavigationPathQueryResult2D::get_path_rids); + + ClassDB::bind_method(D_METHOD("set_path_owner_ids", "path_owner_ids"), &NavigationPathQueryResult2D::set_path_owner_ids); + ClassDB::bind_method(D_METHOD("get_path_owner_ids"), &NavigationPathQueryResult2D::get_path_owner_ids); + ClassDB::bind_method(D_METHOD("reset"), &NavigationPathQueryResult2D::reset); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "path"), "set_path", "get_path"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "path_types"), "set_path_types", "get_path_types"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "path_rids", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_path_rids", "get_path_rids"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT64_ARRAY, "path_owner_ids"), "set_path_owner_ids", "get_path_owner_ids"); + + BIND_ENUM_CONSTANT(PATH_SEGMENT_TYPE_REGION); + BIND_ENUM_CONSTANT(PATH_SEGMENT_TYPE_LINK); } diff --git a/servers/navigation/navigation_path_query_result_2d.h b/servers/navigation/navigation_path_query_result_2d.h index da251ef32d..852a9780ef 100644 --- a/servers/navigation/navigation_path_query_result_2d.h +++ b/servers/navigation/navigation_path_query_result_2d.h @@ -38,15 +38,34 @@ class NavigationPathQueryResult2D : public RefCounted { GDCLASS(NavigationPathQueryResult2D, RefCounted); Vector<Vector2> path; + Vector<int32_t> path_types; + TypedArray<RID> path_rids; + Vector<int64_t> path_owner_ids; protected: static void _bind_methods(); public: + enum PathSegmentType { + PATH_SEGMENT_TYPE_REGION = 0, + PATH_SEGMENT_TYPE_LINK = 1, + }; + void set_path(const Vector<Vector2> &p_path); const Vector<Vector2> &get_path() const; + void set_path_types(const Vector<int32_t> &p_path_types); + const Vector<int32_t> &get_path_types() const; + + void set_path_rids(const TypedArray<RID> &p_path_rids); + TypedArray<RID> get_path_rids() const; + + void set_path_owner_ids(const Vector<int64_t> &p_path_owner_ids); + const Vector<int64_t> &get_path_owner_ids() const; + void reset(); }; +VARIANT_ENUM_CAST(NavigationPathQueryResult2D::PathSegmentType); + #endif // NAVIGATION_PATH_QUERY_RESULT_2D_H diff --git a/servers/navigation/navigation_path_query_result_3d.cpp b/servers/navigation/navigation_path_query_result_3d.cpp index 1e28352995..8218adec18 100644 --- a/servers/navigation/navigation_path_query_result_3d.cpp +++ b/servers/navigation/navigation_path_query_result_3d.cpp @@ -38,15 +38,57 @@ const Vector<Vector3> &NavigationPathQueryResult3D::get_path() const { return path; } +void NavigationPathQueryResult3D::set_path_types(const Vector<int32_t> &p_path_types) { + path_types = p_path_types; +} + +const Vector<int32_t> &NavigationPathQueryResult3D::get_path_types() const { + return path_types; +} + +void NavigationPathQueryResult3D::set_path_rids(const TypedArray<RID> &p_path_rids) { + path_rids = p_path_rids; +} + +TypedArray<RID> NavigationPathQueryResult3D::get_path_rids() const { + return path_rids; +} + +void NavigationPathQueryResult3D::set_path_owner_ids(const Vector<int64_t> &p_path_owner_ids) { + path_owner_ids = p_path_owner_ids; +} + +const Vector<int64_t> &NavigationPathQueryResult3D::get_path_owner_ids() const { + return path_owner_ids; +} + void NavigationPathQueryResult3D::reset() { path.clear(); + path_types.clear(); + path_rids.clear(); + path_owner_ids.clear(); } void NavigationPathQueryResult3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_path", "path"), &NavigationPathQueryResult3D::set_path); ClassDB::bind_method(D_METHOD("get_path"), &NavigationPathQueryResult3D::get_path); + ClassDB::bind_method(D_METHOD("set_path_types", "path_types"), &NavigationPathQueryResult3D::set_path_types); + ClassDB::bind_method(D_METHOD("get_path_types"), &NavigationPathQueryResult3D::get_path_types); + + ClassDB::bind_method(D_METHOD("set_path_rids", "path_rids"), &NavigationPathQueryResult3D::set_path_rids); + ClassDB::bind_method(D_METHOD("get_path_rids"), &NavigationPathQueryResult3D::get_path_rids); + + ClassDB::bind_method(D_METHOD("set_path_owner_ids", "path_owner_ids"), &NavigationPathQueryResult3D::set_path_owner_ids); + ClassDB::bind_method(D_METHOD("get_path_owner_ids"), &NavigationPathQueryResult3D::get_path_owner_ids); + ClassDB::bind_method(D_METHOD("reset"), &NavigationPathQueryResult3D::reset); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "path"), "set_path", "get_path"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "path_types"), "set_path_types", "get_path_types"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "path_rids", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_path_rids", "get_path_rids"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT64_ARRAY, "path_owner_ids"), "set_path_owner_ids", "get_path_owner_ids"); + + BIND_ENUM_CONSTANT(PATH_SEGMENT_TYPE_REGION); + BIND_ENUM_CONSTANT(PATH_SEGMENT_TYPE_LINK); } diff --git a/servers/navigation/navigation_path_query_result_3d.h b/servers/navigation/navigation_path_query_result_3d.h index fc143ac389..ce34e18dc1 100644 --- a/servers/navigation/navigation_path_query_result_3d.h +++ b/servers/navigation/navigation_path_query_result_3d.h @@ -32,21 +32,41 @@ #define NAVIGATION_PATH_QUERY_RESULT_3D_H #include "core/object/ref_counted.h" +#include "core/variant/typed_array.h" #include "servers/navigation/navigation_utilities.h" class NavigationPathQueryResult3D : public RefCounted { GDCLASS(NavigationPathQueryResult3D, RefCounted); Vector<Vector3> path; + Vector<int32_t> path_types; + TypedArray<RID> path_rids; + Vector<int64_t> path_owner_ids; protected: static void _bind_methods(); public: + enum PathSegmentType { + PATH_SEGMENT_TYPE_REGION = 0, + PATH_SEGMENT_TYPE_LINK = 1, + }; + void set_path(const Vector<Vector3> &p_path); const Vector<Vector3> &get_path() const; + void set_path_types(const Vector<int32_t> &p_path_types); + const Vector<int32_t> &get_path_types() const; + + void set_path_rids(const TypedArray<RID> &p_path_rids); + TypedArray<RID> get_path_rids() const; + + void set_path_owner_ids(const Vector<int64_t> &p_path_owner_ids); + const Vector<int64_t> &get_path_owner_ids() const; + void reset(); }; +VARIANT_ENUM_CAST(NavigationPathQueryResult3D::PathSegmentType); + #endif // NAVIGATION_PATH_QUERY_RESULT_3D_H diff --git a/servers/navigation/navigation_utilities.h b/servers/navigation/navigation_utilities.h index e99c139528..c22a2ed952 100644 --- a/servers/navigation/navigation_utilities.h +++ b/servers/navigation/navigation_utilities.h @@ -32,6 +32,7 @@ #define NAVIGATION_UTILITIES_H #include "core/math/vector3.h" +#include "core/variant/typed_array.h" namespace NavigationUtilities { @@ -44,6 +45,19 @@ enum PathPostProcessing { PATH_POSTPROCESSING_EDGECENTERED, }; +enum PathSegmentType { + PATH_SEGMENT_TYPE_REGION = 0, + PATH_SEGMENT_TYPE_LINK +}; + +enum PathMetadataFlags { + PATH_INCLUDE_NONE = 0, + PATH_INCLUDE_TYPES = 1, + PATH_INCLUDE_RIDS = 2, + PATH_INCLUDE_OWNERS = 4, + PATH_INCLUDE_ALL = PATH_INCLUDE_TYPES | PATH_INCLUDE_RIDS | PATH_INCLUDE_OWNERS +}; + struct PathQueryParameters { PathfindingAlgorithm pathfinding_algorithm = PATHFINDING_ALGORITHM_ASTAR; PathPostProcessing path_postprocessing = PATH_POSTPROCESSING_CORRIDORFUNNEL; @@ -51,10 +65,14 @@ struct PathQueryParameters { Vector3 start_position; Vector3 target_position; uint32_t navigation_layers = 1; + BitField<PathMetadataFlags> metadata_flags = PATH_INCLUDE_ALL; }; struct PathQueryResult { Vector<Vector3> path; + Vector<int32_t> path_types; + TypedArray<RID> path_rids; + Vector<int64_t> path_owner_ids; }; } //namespace NavigationUtilities diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index 4ed998a77e..6fd5f222cf 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -154,7 +154,7 @@ static ObjectID id_to_id(const ObjectID &id) { static Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> d) { if (d.is_valid()) { - return d->get_mesh(); + return d->get_navigation_mesh(); } else { return Ref<NavigationMesh>(); } @@ -258,7 +258,7 @@ void NavigationServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("region_set_navigation_layers", "region", "navigation_layers"), &NavigationServer2D::region_set_navigation_layers); ClassDB::bind_method(D_METHOD("region_get_navigation_layers", "region"), &NavigationServer2D::region_get_navigation_layers); ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer2D::region_set_transform); - ClassDB::bind_method(D_METHOD("region_set_navpoly", "region", "nav_poly"), &NavigationServer2D::region_set_navpoly); + ClassDB::bind_method(D_METHOD("region_set_navigation_polygon", "region", "navigation_polygon"), &NavigationServer2D::region_set_navigation_polygon); ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer2D::region_get_connections_count); ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start); ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end); @@ -361,8 +361,8 @@ void FORWARD_2_C(region_set_navigation_layers, RID, p_region, uint32_t, p_naviga uint32_t FORWARD_1_C(region_get_navigation_layers, RID, p_region, rid_to_rid); void FORWARD_2_C(region_set_transform, RID, p_region, Transform2D, p_transform, rid_to_rid, trf2_to_trf3); -void NavigationServer2D::region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const { - NavigationServer3D::get_singleton()->region_set_navmesh(p_region, poly_to_mesh(p_nav_mesh)); +void NavigationServer2D::region_set_navigation_polygon(RID p_region, Ref<NavigationPolygon> p_navigation_polygon) const { + NavigationServer3D::get_singleton()->region_set_navigation_mesh(p_region, poly_to_mesh(p_navigation_polygon)); } int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid); @@ -427,4 +427,7 @@ void NavigationServer2D::query_path(const Ref<NavigationPathQueryParameters2D> & const NavigationUtilities::PathQueryResult _query_result = NavigationServer3D::get_singleton()->_query_path(p_query_parameters->get_parameters()); p_query_result->set_path(vector_v3_to_v2(_query_result.path)); + p_query_result->set_path_types(_query_result.path_types); + p_query_result->set_path_rids(_query_result.path_rids); + p_query_result->set_path_owner_ids(_query_result.path_owner_ids); } diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index cf6011a0f9..9b921969c0 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -34,7 +34,7 @@ #include "core/object/class_db.h" #include "core/templates/rid.h" -#include "scene/2d/navigation_region_2d.h" +#include "scene/resources/navigation_polygon.h" #include "servers/navigation/navigation_path_query_parameters_2d.h" #include "servers/navigation/navigation_path_query_result_2d.h" @@ -126,7 +126,7 @@ public: virtual void region_set_transform(RID p_region, Transform2D p_transform) const; /// Set the navigation poly of this region. - virtual void region_set_navpoly(RID p_region, Ref<NavigationPolygon> p_nav_mesh) const; + virtual void region_set_navigation_polygon(RID p_region, Ref<NavigationPolygon> p_navigation_polygon) const; /// Get a list of a region's connection to other regions. virtual int region_get_connections_count(RID p_region) const; diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 940dd61f67..6ad07d3053 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -77,8 +77,8 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("region_set_navigation_layers", "region", "navigation_layers"), &NavigationServer3D::region_set_navigation_layers); ClassDB::bind_method(D_METHOD("region_get_navigation_layers", "region"), &NavigationServer3D::region_get_navigation_layers); ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer3D::region_set_transform); - ClassDB::bind_method(D_METHOD("region_set_navmesh", "region", "nav_mesh"), &NavigationServer3D::region_set_navmesh); - ClassDB::bind_method(D_METHOD("region_bake_navmesh", "mesh", "node"), &NavigationServer3D::region_bake_navmesh); + ClassDB::bind_method(D_METHOD("region_set_navigation_mesh", "region", "navigation_mesh"), &NavigationServer3D::region_set_navigation_mesh); + ClassDB::bind_method(D_METHOD("region_bake_navigation_mesh", "navigation_mesh", "root_node"), &NavigationServer3D::region_bake_navigation_mesh); ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer3D::region_get_connections_count); ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_start); ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_end); @@ -155,7 +155,7 @@ NavigationServer3D::NavigationServer3D() { debug_navigation_enable_link_connections_xray = GLOBAL_DEF("debug/shapes/navigation/enable_link_connections_xray", true); if (Engine::get_singleton()->is_editor_hint()) { - // enable NavigationServer3D when in Editor or else navmesh edge connections are invisible + // enable NavigationServer3D when in Editor or else navigation mesh edge connections are invisible // on runtime tests SceneTree has "Visible Navigation" set and main iteration takes care of this set_debug_enabled(true); } @@ -491,4 +491,7 @@ void NavigationServer3D::query_path(const Ref<NavigationPathQueryParameters3D> & const NavigationUtilities::PathQueryResult _query_result = _query_path(p_query_parameters->get_parameters()); p_query_result->set_path(_query_result.path); + p_query_result->set_path_types(_query_result.path_types); + p_query_result->set_path_rids(_query_result.path_rids); + p_query_result->set_path_owner_ids(_query_result.path_owner_ids); } diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index bf4c22be8a..65d6d19073 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -138,10 +138,10 @@ public: virtual void region_set_transform(RID p_region, Transform3D p_transform) const = 0; /// Set the navigation mesh of this region. - virtual void region_set_navmesh(RID p_region, Ref<NavigationMesh> p_nav_mesh) const = 0; + virtual void region_set_navigation_mesh(RID p_region, Ref<NavigationMesh> p_navigation_mesh) const = 0; /// Bake the navigation mesh. - virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const = 0; + virtual void region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) const = 0; /// Get a list of a region's connection to other regions. virtual int region_get_connections_count(RID p_region) const = 0; diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index c5a93cc390..20f23ae031 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -765,6 +765,9 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("joint_set_param", "joint", "param", "value"), &PhysicsServer2D::joint_set_param); ClassDB::bind_method(D_METHOD("joint_get_param", "joint", "param"), &PhysicsServer2D::joint_get_param); + ClassDB::bind_method(D_METHOD("joint_disable_collisions_between_bodies", "joint", "disable"), &PhysicsServer2D::joint_disable_collisions_between_bodies); + ClassDB::bind_method(D_METHOD("joint_is_disabled_collisions_between_bodies", "joint"), &PhysicsServer2D::joint_is_disabled_collisions_between_bodies); + ClassDB::bind_method(D_METHOD("joint_make_pin", "joint", "anchor", "body_a", "body_b"), &PhysicsServer2D::joint_make_pin, DEFVAL(RID())); ClassDB::bind_method(D_METHOD("joint_make_groove", "joint", "groove1_a", "groove2_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_groove, DEFVAL(RID()), DEFVAL(RID())); ClassDB::bind_method(D_METHOD("joint_make_damped_spring", "joint", "anchor_a", "anchor_b", "body_a", "body_b"), &PhysicsServer2D::joint_make_damped_spring, DEFVAL(RID())); diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index aecb687d5f..25912e9aca 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -943,6 +943,9 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("joint_set_solver_priority", "joint", "priority"), &PhysicsServer3D::joint_set_solver_priority); ClassDB::bind_method(D_METHOD("joint_get_solver_priority", "joint"), &PhysicsServer3D::joint_get_solver_priority); + ClassDB::bind_method(D_METHOD("joint_disable_collisions_between_bodies", "joint", "disable"), &PhysicsServer3D::joint_disable_collisions_between_bodies); + ClassDB::bind_method(D_METHOD("joint_is_disabled_collisions_between_bodies", "joint"), &PhysicsServer3D::joint_is_disabled_collisions_between_bodies); + ClassDB::bind_method(D_METHOD("joint_make_generic_6dof", "joint", "body_A", "local_ref_A", "body_B", "local_ref_B"), &PhysicsServer3D::joint_make_generic_6dof); ClassDB::bind_method(D_METHOD("generic_6dof_joint_set_param", "joint", "axis", "param", "value"), &PhysicsServer3D::generic_6dof_joint_set_param); diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index 3937362920..918f5c1fb7 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -49,6 +49,7 @@ public: virtual void set_surface_materials(const Vector<RID> &p_materials) override {} virtual void set_mesh_instance(RID p_mesh_instance) override {} virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override {} + virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) override {} virtual void set_lod_bias(float p_lod_bias) override {} virtual void set_layer_mask(uint32_t p_layer_mask) override {} virtual void set_fade_range(bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override {} diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 33f1f38bf5..6be0419d98 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -1185,7 +1185,7 @@ void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p rect->texture = p_texture; } -void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, int p_outline_size, float p_px_range) { +void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, int p_outline_size, float p_px_range, float p_scale) { Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); @@ -1215,7 +1215,7 @@ void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, co rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V; rect->source.size.y = -rect->source.size.y; } - rect->outline = p_outline_size; + rect->outline = (float)p_outline_size / p_scale / 4.0; rect->px_range = p_px_range; } diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 198e1020f0..808c0acc35 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -228,7 +228,7 @@ public: void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false); - void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0); + void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0); void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)); void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode = RS::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)); void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0); diff --git a/servers/rendering/renderer_geometry_instance.cpp b/servers/rendering/renderer_geometry_instance.cpp index 675659f4c8..f4681916f4 100644 --- a/servers/rendering/renderer_geometry_instance.cpp +++ b/servers/rendering/renderer_geometry_instance.cpp @@ -80,6 +80,11 @@ void RenderGeometryInstanceBase::set_transform(const Transform3D &p_transform, c lod_model_scale = max_scale; } +void RenderGeometryInstanceBase::set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) { + sorting_offset = p_sorting_offset; + use_aabb_center = p_use_aabb_center; +} + void RenderGeometryInstanceBase::set_lod_bias(float p_lod_bias) { lod_bias = p_lod_bias; } diff --git a/servers/rendering/renderer_geometry_instance.h b/servers/rendering/renderer_geometry_instance.h index fecb9878c2..37fde9e1f6 100644 --- a/servers/rendering/renderer_geometry_instance.h +++ b/servers/rendering/renderer_geometry_instance.h @@ -50,6 +50,7 @@ public: virtual void set_surface_materials(const Vector<RID> &p_materials) = 0; virtual void set_mesh_instance(RID p_mesh_instance) = 0; virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) = 0; + virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) = 0; virtual void set_lod_bias(float p_lod_bias) = 0; virtual void set_layer_mask(uint32_t p_layer_mask) = 0; virtual void set_fade_range(bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) = 0; @@ -86,11 +87,13 @@ public: RID mesh_instance; Transform3D transform; - bool mirror = false; // move into data? - AABB transformed_aabb; //needed for LOD + bool mirror = false; + AABB transformed_aabb; bool non_uniform_scale = false; float lod_model_scale = 1.0; float lod_bias = 0.0; + float sorting_offset = 0.0; + bool use_aabb_center = true; uint32_t layer_mask = 1; @@ -133,6 +136,7 @@ public: virtual void set_surface_materials(const Vector<RID> &p_materials) override; virtual void set_mesh_instance(RID p_mesh_instance) override; virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override; + virtual void set_pivot_data(float p_sorting_offset, bool p_use_aabb_center) override; virtual void set_lod_bias(float p_lod_bias) override; virtual void set_layer_mask(uint32_t p_layer_mask) override; virtual void set_fade_range(bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index c853ae6c69..608f7ff958 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -831,8 +831,18 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con for (int i = 0; i < (int)p_render_data->instances->size(); i++) { GeometryInstanceForwardClustered *inst = static_cast<GeometryInstanceForwardClustered *>((*p_render_data->instances)[i]); - Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); - inst->depth = near_plane.distance_to(support_min); + Vector3 center = inst->transform.origin; + if (p_render_data->scene_data->cam_orthogonal) { + if (inst->use_aabb_center) { + center = inst->transformed_aabb.get_support(-near_plane.normal); + } + inst->depth = near_plane.distance_to(center) - inst->sorting_offset; + } else { + if (inst->use_aabb_center) { + center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5); + } + inst->depth = p_render_data->scene_data->cam_transform.origin.distance_to(center) - inst->sorting_offset; + } uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); uint32_t flags = inst->base_flags; //fill flags if appropriate @@ -3598,6 +3608,10 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p } ginstance->transforms_uniform_set = particles_storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); + if (particles_storage->particles_get_frame_counter(ginstance->data->base) == 0) { + // Particles haven't been cleared or updated, update once now to ensure they are ready to render. + particles_storage->update_particles(); + } } else if (ginstance->data->base_type == RS::INSTANCE_MESH) { if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) { ginstance->transforms_uniform_set = mesh_storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 350a5eb0e4..e47ca8dd73 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -154,8 +154,8 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RenderSceneBu render_buffers->create_texture(RB_SCOPE_MOBILE, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples); - format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; + format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, usage_bits) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; render_buffers->create_texture(RB_SCOPE_MOBILE, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples); } @@ -1757,8 +1757,18 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const for (int i = 0; i < (int)p_render_data->instances->size(); i++) { GeometryInstanceForwardMobile *inst = static_cast<GeometryInstanceForwardMobile *>((*p_render_data->instances)[i]); - Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal); - inst->depth = near_plane.distance_to(support_min); + Vector3 center = inst->transform.origin; + if (p_render_data->scene_data->cam_orthogonal) { + if (inst->use_aabb_center) { + center = inst->transformed_aabb.get_support(-near_plane.normal); + } + inst->depth = near_plane.distance_to(center) - inst->sorting_offset; + } else { + if (inst->use_aabb_center) { + center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5); + } + inst->depth = p_render_data->scene_data->cam_transform.origin.distance_to(center) - inst->sorting_offset; + } uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15); uint32_t flags = inst->base_flags; //fill flags if appropriate @@ -2626,6 +2636,10 @@ void RenderForwardMobile::_geometry_instance_update(RenderGeometryInstance *p_ge } ginstance->transforms_uniform_set = particles_storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); + if (particles_storage->particles_get_frame_counter(ginstance->data->base) == 0) { + // Particles haven't been cleared or updated, update once now to ensure they are ready to render. + particles_storage->update_particles(); + } } else if (ginstance->data->base_type == RS::INSTANCE_MESH) { if (mesh_storage->skeleton_is_valid(ginstance->data->skeleton)) { ginstance->transforms_uniform_set = mesh_storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET); diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index f7302adbf6..96690ceac1 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -790,7 +790,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend ERR_BREAK(particles_storage->particles_get_mode(pt->particles) != RS::PARTICLES_MODE_2D); particles_storage->particles_request_process(pt->particles); - if (particles_storage->particles_is_inactive(pt->particles)) { + if (particles_storage->particles_is_inactive(pt->particles) || particles_storage->particles_get_frame_counter(pt->particles) == 0) { break; } diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index 9f6aa7adc0..a609076e2c 100644 --- a/servers/rendering/renderer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -243,8 +243,14 @@ void main() { if (params.trail_size > 1) { if (params.trail_pass) { + if (particle >= params.total_particles * (params.trail_size - 1)) { + return; + } particle += (particle / (params.trail_size - 1)) + 1; } else { + if (particle >= params.total_particles) { + return; + } particle *= params.trail_size; } } @@ -298,12 +304,17 @@ void main() { PARTICLE.flags = PARTICLE_FLAG_TRAILED | ((frame_history.data[0].frame & PARTICLE_FRAME_MASK) << PARTICLE_FRAME_SHIFT); //mark it as trailed, save in which frame it will start PARTICLE.xform = particles.data[src_idx].xform; } - + if (!bool(particles.data[src_idx].flags & PARTICLE_FLAG_ACTIVE)) { + // Disable the entire trail if the parent is no longer active. + PARTICLE.flags = 0; + return; + } if (bool(PARTICLE.flags & PARTICLE_FLAG_TRAILED) && ((PARTICLE.flags >> PARTICLE_FRAME_SHIFT) == (FRAME.frame & PARTICLE_FRAME_MASK))) { //check this is trailed and see if it should start now // we just assume that this is the first frame of the particle, the rest is deterministic PARTICLE.flags = PARTICLE_FLAG_ACTIVE | (particles.data[src_idx].flags & (PARTICLE_FRAME_MASK << PARTICLE_FRAME_SHIFT)); return; //- this appears like it should be correct, but it seems not to be.. wonder why. } + } else { PARTICLE.flags &= ~PARTICLE_FLAG_STARTED; } diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 1dd95969e6..ff882c1992 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -1726,13 +1726,13 @@ void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_use //erase lightmap users if (lm->light_texture.is_valid()) { - TextureStorage::Texture *t = texture_storage->get_singleton()->get_texture(lm->light_texture); + TextureStorage::Texture *t = texture_storage->get_texture(lm->light_texture); if (t) { t->lightmap_users.erase(p_lightmap); } } - TextureStorage::Texture *t = texture_storage->get_singleton()->get_texture(p_light); + TextureStorage::Texture *t = texture_storage->get_texture(p_light); lm->light_texture = p_light; lm->uses_spherical_harmonics = p_uses_spherical_haromics; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 1e91982fe1..708455706b 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -1415,6 +1415,7 @@ void ParticlesStorage::update_particles() { } bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0; + bool updated = false; if (particles->clear && particles->pre_process_time > 0.0) { double frame_time; @@ -1429,6 +1430,7 @@ void ParticlesStorage::update_particles() { while (todo >= 0) { _particles_process(particles, frame_time); todo -= frame_time; + updated = true; } } @@ -1450,9 +1452,10 @@ void ParticlesStorage::update_particles() { } double todo = particles->frame_remainder + delta; - while (todo >= frame_time) { + while (todo >= frame_time || (particles->clear && !updated)) { _particles_process(particles, frame_time); todo -= decr; + updated = true; } particles->frame_remainder = todo; @@ -1460,14 +1463,16 @@ void ParticlesStorage::update_particles() { } else { if (zero_time_scale) { _particles_process(particles, 0.0); + updated = true; } else { _particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time()); + updated = true; } } //copy particles to instance buffer - if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { + if (updated && particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { //does not need view dependent operation, do copy here ParticlesShader::CopyPushConstant copy_push_constant; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index ef3299ba1e..0701dc95dd 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -455,6 +455,12 @@ public: return particles->mode; } + _FORCE_INLINE_ uint32_t particles_get_frame_counter(RID p_particles) { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_COND_V(!particles, false); + return particles->frame_counter; + } + _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles, uint32_t &r_trail_divisor) { Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, 0); @@ -485,9 +491,8 @@ public: _FORCE_INLINE_ RID particles_get_instance_buffer_uniform_set(RID p_particles, RID p_shader, uint32_t p_set) { Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, RID()); - if (particles->particles_transforms_buffer_uniform_set.is_null()) { + if (particles->particles_transforms_buffer_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(particles->particles_transforms_buffer_uniform_set)) { _particles_update_buffers(particles); - Vector<RD::Uniform> uniforms; { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 67f013cfb0..6a4359faf3 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1777,6 +1777,46 @@ Ref<Image> TextureStorage::_validate_texture_format(const Ref<Image> &p_image, T r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; } break; + case Image::FORMAT_ASTC_4x4: + case Image::FORMAT_ASTC_4x4_HDR: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ASTC_4x4_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ASTC_4x4_UNORM_BLOCK; + if (p_image->get_format() == Image::FORMAT_ASTC_4x4) { + r_format.format_srgb = RD::DATA_FORMAT_ASTC_4x4_SRGB_BLOCK; + } + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; // astc 4x4 + case Image::FORMAT_ASTC_8x8: + case Image::FORMAT_ASTC_8x8_HDR: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK; + if (p_image->get_format() == Image::FORMAT_ASTC_8x8) { + r_format.format_srgb = RD::DATA_FORMAT_ASTC_8x8_SRGB_BLOCK; + } + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; // astc 8x8 default: { } diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index cfc25fc577..a378c3fde8 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -646,6 +646,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { geom->geometry_instance->set_surface_materials(instance->materials); geom->geometry_instance->set_transform(instance->transform, instance->aabb, instance->transformed_aabb); geom->geometry_instance->set_layer_mask(instance->layer_mask); + geom->geometry_instance->set_pivot_data(instance->sorting_offset, instance->use_aabb_center); geom->geometry_instance->set_lod_bias(instance->lod_bias); geom->geometry_instance->set_transparency(instance->transparency); geom->geometry_instance->set_use_baked_light(instance->baked_light); @@ -844,6 +845,20 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) } } +void RendererSceneCull::instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) { + Instance *instance = instance_owner.get_or_null(p_instance); + ERR_FAIL_COND(!instance); + + instance->sorting_offset = p_sorting_offset; + instance->use_aabb_center = p_use_aabb_center; + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + ERR_FAIL_NULL(geom->geometry_instance); + geom->geometry_instance->set_pivot_data(p_sorting_offset, p_use_aabb_center); + } +} + void RendererSceneCull::instance_geometry_set_transparency(RID p_instance, float p_transparency) { Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 51f800381b..106871edfd 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -459,6 +459,10 @@ public: float extra_margin; ObjectID object_id; + // sorting + float sorting_offset = 0.0; + bool use_aabb_center = true; + Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior uint64_t last_frame_pass; @@ -933,6 +937,7 @@ public: virtual void instance_set_base(RID p_instance, RID p_base); virtual void instance_set_scenario(RID p_instance, RID p_scenario); virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask); + virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center); virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform); virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id); virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h index 51b9cb2bcf..e3f29b51d5 100644 --- a/servers/rendering/rendering_method.h +++ b/servers/rendering/rendering_method.h @@ -72,6 +72,7 @@ public: virtual void instance_set_base(RID p_instance, RID p_base) = 0; virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0; virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0; + virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) = 0; virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0; virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0; virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 662b582411..3f5b135d2a 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -762,6 +762,7 @@ public: FUNC2(instance_set_base, RID, RID) FUNC2(instance_set_scenario, RID, RID) FUNC2(instance_set_layer_mask, RID, uint32_t) + FUNC3(instance_set_pivot_data, RID, float, bool) FUNC2(instance_set_transform, RID, const Transform3D &) FUNC2(instance_attach_object_instance_id, RID, ObjectID) FUNC3(instance_set_blend_shape_weight, RID, int, float) @@ -850,7 +851,7 @@ public: FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &) FUNC6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool) FUNC7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool) - FUNC7(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float) + FUNC8(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float, float) FUNC5(canvas_item_add_lcd_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &) FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &) FUNC6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float) diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 3604756fd8..00b6a8c44c 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -134,6 +134,8 @@ static String _interpstr(SL::DataInterpolation p_interp) { return "flat "; case SL::INTERPOLATION_SMOOTH: return ""; + case SL::INTERPOLATION_DEFAULT: + return ""; } return ""; } @@ -667,6 +669,9 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene fragment_varyings.insert(varying_name); continue; } + if (varying.type < SL::TYPE_INT) { + continue; // Ignore boolean types to prevent crashing (if varying is just declared). + } String vcode; String interp_mode = _interpstr(varying.interpolation); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index e451fb35c2..8c732b3d5a 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -989,6 +989,18 @@ String ShaderLanguage::get_precision_name(DataPrecision p_type) { return ""; } +String ShaderLanguage::get_interpolation_name(DataInterpolation p_interpolation) { + switch (p_interpolation) { + case INTERPOLATION_FLAT: + return "flat"; + case INTERPOLATION_SMOOTH: + return "smooth"; + default: + break; + } + return ""; +} + String ShaderLanguage::get_datatype_name(DataType p_type) { switch (p_type) { case TYPE_VOID: @@ -4417,13 +4429,17 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const { } bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message) { - if (current_function != String("vertex") && current_function != String("fragment")) { + if (current_function != "vertex" && current_function != "fragment") { *r_message = vformat(RTR("Varying may not be assigned in the '%s' function."), current_function); return false; } switch (p_varying.stage) { case ShaderNode::Varying::STAGE_UNKNOWN: // first assign if (current_function == varying_function_names.vertex) { + if (p_varying.type < TYPE_INT) { + *r_message = vformat(RTR("Varying with '%s' data type may only be assigned in the 'fragment' function."), get_datatype_name(p_varying.type)); + return false; + } p_varying.stage = ShaderNode::Varying::STAGE_VERTEX; } else if (current_function == varying_function_names.fragment) { p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT; @@ -5223,7 +5239,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (shader->varyings.has(varname)) { switch (shader->varyings[varname].stage) { case ShaderNode::Varying::STAGE_UNKNOWN: { - _set_error(vformat(RTR("Varying '%s' must be assigned in the vertex or fragment function first."), varname)); + _set_error(vformat(RTR("Varying '%s' must be assigned in the 'vertex' or 'fragment' function first."), varname)); return nullptr; } case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT: @@ -5407,6 +5423,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } } else { switch (var.stage) { + case ShaderNode::Varying::STAGE_UNKNOWN: { + if (var.type < TYPE_INT) { + if (current_function == varying_function_names.vertex) { + _set_error(vformat(RTR("Varying with '%s' data type may only be used in the 'fragment' function."), get_datatype_name(var.type))); + } else { + _set_error(vformat(RTR("Varying '%s' must be assigned in the 'fragment' function first."), identifier)); + } + return nullptr; + } + } break; case ShaderNode::Varying::STAGE_VERTEX: if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) { var.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT; @@ -8225,7 +8251,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f } } DataPrecision precision = PRECISION_DEFAULT; - DataInterpolation interpolation = INTERPOLATION_SMOOTH; + DataInterpolation interpolation = INTERPOLATION_DEFAULT; DataType type; StringName name; int array_size = 0; @@ -8334,6 +8360,11 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f return ERR_PARSE_ERROR; } + if (!is_uniform && interpolation != INTERPOLATION_DEFAULT && type < TYPE_INT) { + _set_error(vformat(RTR("Interpolation modifier '%s' cannot be used with boolean types."), get_interpolation_name(interpolation))); + return ERR_PARSE_ERROR; + } + if (!is_uniform && type > TYPE_MAT4) { _set_error(RTR("Invalid data type for varying.")); return ERR_PARSE_ERROR; diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 9c3cc9c5cd..d34114589f 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -247,6 +247,7 @@ public: enum DataInterpolation { INTERPOLATION_FLAT, INTERPOLATION_SMOOTH, + INTERPOLATION_DEFAULT, }; enum Operator { @@ -774,6 +775,7 @@ public: static bool is_token_arg_qual(TokenType p_type); static DataPrecision get_token_precision(TokenType p_type); static String get_precision_name(DataPrecision p_type); + static String get_interpolation_name(DataInterpolation p_interpolation); static String get_datatype_name(DataType p_type); static String get_uniform_hint_name(ShaderNode::Uniform::Hint p_hint); static String get_texture_filter_name(TextureFilter p_filter); diff --git a/servers/rendering/storage/environment_storage.cpp b/servers/rendering/storage/environment_storage.cpp index 9b1842f1d9..78ce4eb4d0 100644 --- a/servers/rendering/storage/environment_storage.cpp +++ b/servers/rendering/storage/environment_storage.cpp @@ -283,7 +283,7 @@ void RendererEnvironmentStorage::environment_set_volumetric_fog(RID p_env, bool env->volumetric_fog_scattering = p_albedo; env->volumetric_fog_emission = p_emission; env->volumetric_fog_emission_energy = p_emission_energy; - env->volumetric_fog_anisotropy = p_anisotropy, + env->volumetric_fog_anisotropy = p_anisotropy; env->volumetric_fog_length = p_length; env->volumetric_fog_detail_spread = p_detail_spread; env->volumetric_fog_gi_inject = p_gi_inject; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 8d6d756edc..de3bd8d3e0 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2480,6 +2480,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("instance_set_base", "instance", "base"), &RenderingServer::instance_set_base); ClassDB::bind_method(D_METHOD("instance_set_scenario", "instance", "scenario"), &RenderingServer::instance_set_scenario); ClassDB::bind_method(D_METHOD("instance_set_layer_mask", "instance", "mask"), &RenderingServer::instance_set_layer_mask); + ClassDB::bind_method(D_METHOD("instance_set_pivot_data", "instance", "sorting_offset", "use_aabb_center"), &RenderingServer::instance_set_pivot_data); ClassDB::bind_method(D_METHOD("instance_set_transform", "instance", "transform"), &RenderingServer::instance_set_transform); ClassDB::bind_method(D_METHOD("instance_attach_object_instance_id", "instance", "id"), &RenderingServer::instance_attach_object_instance_id); ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight); @@ -2596,7 +2597,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect); ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle); ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("canvas_item_add_msdf_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "outline_size", "px_range"), &RenderingServer::canvas_item_add_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("canvas_item_add_msdf_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "outline_size", "px_range", "scale"), &RenderingServer::canvas_item_add_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(1.0), DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("canvas_item_add_lcd_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate"), &RenderingServer::canvas_item_add_lcd_texture_rect_region); ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1))); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 1d74bb54b9..f3d95e07cb 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1209,6 +1209,7 @@ public: virtual void instance_set_base(RID p_instance, RID p_base) = 0; virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0; virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0; + virtual void instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) = 0; virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0; virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0; virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0; @@ -1339,7 +1340,7 @@ public: virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) = 0; virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false) = 0; - virtual void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0) = 0; + virtual void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0) = 0; virtual void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)) = 0; virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)) = 0; virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0) = 0; diff --git a/tests/core/config/test_project_settings.h b/tests/core/config/test_project_settings.h new file mode 100644 index 0000000000..c99ba76a24 --- /dev/null +++ b/tests/core/config/test_project_settings.h @@ -0,0 +1,102 @@ +/*************************************************************************/ +/* test_project_settings.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_PROJECT_SETTINGS_H +#define TEST_PROJECT_SETTINGS_H + +#include "core/config/project_settings.h" +#include "core/variant/variant.h" +#include "tests/test_macros.h" + +namespace TestProjectSettings { + +TEST_CASE("[ProjectSettings] Get existing setting") { + CHECK(ProjectSettings::get_singleton()->has_setting("application/config/name")); + + Variant variant = ProjectSettings::get_singleton()->get_setting("application/config/name"); + CHECK_EQ(variant.get_type(), Variant::STRING); + + String name = variant; + CHECK_EQ(name, "GDScript Integration Test Suite"); +} + +TEST_CASE("[ProjectSettings] Default value is ignored if setting exists") { + CHECK(ProjectSettings::get_singleton()->has_setting("application/config/name")); + + Variant variant = ProjectSettings::get_singleton()->get_setting("application/config/name", "SomeDefaultValue"); + CHECK_EQ(variant.get_type(), Variant::STRING); + + String name = variant; + CHECK_EQ(name, "GDScript Integration Test Suite"); +} + +TEST_CASE("[ProjectSettings] Non existing setting is null") { + CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("not_existing_setting")); + + Variant variant = ProjectSettings::get_singleton()->get_setting("not_existing_setting"); + CHECK_EQ(variant.get_type(), Variant::NIL); +} + +TEST_CASE("[ProjectSettings] Non existing setting should return default value") { + CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("not_existing_setting")); + + Variant variant = ProjectSettings::get_singleton()->get_setting("not_existing_setting"); + CHECK_EQ(variant.get_type(), Variant::NIL); + + variant = ProjectSettings::get_singleton()->get_setting("not_existing_setting", "my_nice_default_value"); + CHECK_EQ(variant.get_type(), Variant::STRING); + + String name = variant; + CHECK_EQ(name, "my_nice_default_value"); + + CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("not_existing_setting")); +} + +TEST_CASE("[ProjectSettings] Set value should be returned when retrieved") { + CHECK_FALSE(ProjectSettings::get_singleton()->has_setting("my_custom_setting")); + + Variant variant = ProjectSettings::get_singleton()->get_setting("my_custom_setting"); + CHECK_EQ(variant.get_type(), Variant::NIL); + + ProjectSettings::get_singleton()->set_setting("my_custom_setting", true); + CHECK(ProjectSettings::get_singleton()->has_setting("my_custom_setting")); + + variant = ProjectSettings::get_singleton()->get_setting("my_custom_setting"); + CHECK_EQ(variant.get_type(), Variant::BOOL); + + bool value = variant; + CHECK_EQ(true, value); + + CHECK(ProjectSettings::get_singleton()->has_setting("my_custom_setting")); +} + +} // namespace TestProjectSettings + +#endif // TEST_PROJECT_SETTINGS_H diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h index 326b55d07a..fa31a3a461 100644 --- a/tests/scene/test_code_edit.h +++ b/tests/scene/test_code_edit.h @@ -2871,6 +2871,89 @@ TEST_CASE("[SceneTree][CodeEdit] completion") { CHECK(code_edit->get_text() == "\'\'\'"); } + SUBCASE("[CodeEdit] autocomplete with brace completion") { + code_edit->set_auto_brace_completion_enabled(true); + CHECK(code_edit->is_auto_brace_completion_enabled()); + + code_edit->insert_text_at_caret("(te)"); + code_edit->set_caret_column(3); + + // Full completion. + code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test()", "test()"); + code_edit->update_code_completion_options(); + code_edit->confirm_code_completion(); + CHECK(code_edit->get_line(0) == "(test())"); + CHECK(code_edit->get_caret_column() == 7); + code_edit->undo(); + + // With "arg". + code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test(", "test("); + code_edit->update_code_completion_options(); + code_edit->confirm_code_completion(); + CHECK(code_edit->get_line(0) == "(test())"); + CHECK(code_edit->get_caret_column() == 6); + code_edit->undo(); + + // brace completion disbaled + code_edit->set_auto_brace_completion_enabled(false); + + // Full completion. + code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test()", "test()"); + code_edit->update_code_completion_options(); + code_edit->confirm_code_completion(); + CHECK(code_edit->get_line(0) == "(test())"); + CHECK(code_edit->get_caret_column() == 7); + code_edit->undo(); + + // With "arg". + code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_FUNCTION, "test(", "test("); + code_edit->update_code_completion_options(); + code_edit->confirm_code_completion(); + CHECK(code_edit->get_line(0) == "(test()"); + CHECK(code_edit->get_caret_column() == 6); + + // String + code_edit->set_auto_brace_completion_enabled(true); + code_edit->clear(); + code_edit->insert_text_at_caret("\"\""); + code_edit->set_caret_column(1); + + // Full completion. + code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test\"", "\"test\""); + code_edit->update_code_completion_options(); + code_edit->confirm_code_completion(); + CHECK(code_edit->get_line(0) == "\"test\""); + CHECK(code_edit->get_caret_column() == 6); + code_edit->undo(); + + // With "arg". + code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test", "\"test"); + code_edit->update_code_completion_options(); + code_edit->confirm_code_completion(); + CHECK(code_edit->get_line(0) == "\"\"test\"\""); + CHECK(code_edit->get_caret_column() == 7); + code_edit->undo(); + + // brace completion disbaled + code_edit->set_auto_brace_completion_enabled(false); + + // Full completion. + code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test\"", "\"test\""); + code_edit->update_code_completion_options(); + code_edit->confirm_code_completion(); + CHECK(code_edit->get_line(0) == "\"test\""); + CHECK(code_edit->get_caret_column() == 6); + code_edit->undo(); + + // With "arg". + code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test", "\"test"); + code_edit->update_code_completion_options(); + code_edit->confirm_code_completion(); + CHECK(code_edit->get_line(0) == "\"\"test\""); + CHECK(code_edit->get_caret_column() == 7); + code_edit->undo(); + } + SUBCASE("[CodeEdit] autocomplete") { code_edit->set_code_completion_enabled(true); CHECK(code_edit->is_code_completion_enabled()); diff --git a/tests/test_main.cpp b/tests/test_main.cpp index d58c19ac32..4c4d47a7ae 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -30,6 +30,7 @@ #include "test_main.h" +#include "tests/core/config/test_project_settings.h" #include "tests/core/input/test_input_event_key.h" #include "tests/core/input/test_shortcut.h" #include "tests/core/io/test_config_file.h" diff --git a/thirdparty/README.md b/thirdparty/README.md index 8b73927050..017dabe9e5 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -345,7 +345,7 @@ Files extracted from upstream source: ## mbedtls - Upstream: https://github.com/Mbed-TLS/mbedtls -- Version: 2.18.1 (dd79db10014d85b26d11fe57218431f2e5ede6f2, 2022) +- Version: 2.18.2 (89f040a5c938985c5f30728baed21e49d0846a53, 2022) - License: Apache 2.0 File extracted from upstream release tarball: @@ -355,12 +355,10 @@ File extracted from upstream release tarball: - The `LICENSE` file. - Applied the patch in `patches/1453.diff` (upstream PR: https://github.com/ARMmbed/mbedtls/pull/1453). + Applied the patch in `patches/windows-arm64-hardclock.diff` - Added 2 files `godot_core_mbedtls_platform.c` and `godot_core_mbedtls_config.h` providing configuration for light bundling with core. -Some changes have been made in order to fix Windows on ARM build errors. -They are marked with `// -- GODOT start --` and `// -- GODOT end --` - ## meshoptimizer diff --git a/thirdparty/libpng/arm/arm_init.c b/thirdparty/libpng/arm/arm_init.c index ab22525b38..84d05556f8 100644 --- a/thirdparty/libpng/arm/arm_init.c +++ b/thirdparty/libpng/arm/arm_init.c @@ -36,7 +36,10 @@ #ifndef PNG_ARM_NEON_FILE # if defined(__aarch64__) || defined(_M_ARM64) /* ARM Neon is expected to be unconditionally available on ARM64. */ -# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this platform" +# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on ARM64" +# elif defined(__ARM_NEON__) || defined(__ARM_NEON) + /* ARM Neon is expected to be available on the target CPU architecture. */ +# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this CPU arch" # elif defined(__linux__) # define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c" # else diff --git a/thirdparty/libpng/png.c b/thirdparty/libpng/png.c index fc09564262..4f3e8bbd31 100644 --- a/thirdparty/libpng/png.c +++ b/thirdparty/libpng/png.c @@ -14,7 +14,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_38 Your_png_h_is_not_version_1_6_38; +typedef png_libpng_version_1_6_39 Your_png_h_is_not_version_1_6_39; #ifdef __GNUC__ /* The version tests may need to be added to, but the problem warning has @@ -815,7 +815,7 @@ png_get_copyright(png_const_structrp png_ptr) return PNG_STRING_COPYRIGHT #else return PNG_STRING_NEWLINE \ - "libpng version 1.6.38" PNG_STRING_NEWLINE \ + "libpng version 1.6.39" PNG_STRING_NEWLINE \ "Copyright (c) 2018-2022 Cosmin Truta" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \ PNG_STRING_NEWLINE \ @@ -2710,7 +2710,7 @@ png_check_IHDR(png_const_structrp png_ptr, int /* PRIVATE */ png_check_fp_number(png_const_charp string, size_t size, int *statep, - png_size_tp whereami) + size_t *whereami) { int state = *statep; size_t i = *whereami; diff --git a/thirdparty/libpng/png.h b/thirdparty/libpng/png.h index 5fb494fb1a..f109cdf336 100644 --- a/thirdparty/libpng/png.h +++ b/thirdparty/libpng/png.h @@ -1,7 +1,7 @@ /* png.h - header file for PNG reference library * - * libpng version 1.6.38 - September 14, 2022 + * libpng version 1.6.39 - November 20, 2022 * * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson @@ -15,7 +15,7 @@ * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger * libpng versions 0.97, January 1998, through 1.6.35, July 2018: * Glenn Randers-Pehrson - * libpng versions 1.6.36, December 2018, through 1.6.38, September 2022: + * libpng versions 1.6.36, December 2018, through 1.6.39, November 2022: * Cosmin Truta * See also "Contributing Authors", below. */ @@ -239,7 +239,7 @@ * ... * 1.5.30 15 10530 15.so.15.30[.0] * ... - * 1.6.38 16 10638 16.so.16.38[.0] + * 1.6.39 16 10639 16.so.16.39[.0] * * Henceforth the source version will match the shared-library major and * minor numbers; the shared-library major version number will be used for @@ -278,8 +278,8 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.6.38" -#define PNG_HEADER_VERSION_STRING " libpng version 1.6.38 - September 14, 2022\n" +#define PNG_LIBPNG_VER_STRING "1.6.39" +#define PNG_HEADER_VERSION_STRING " libpng version 1.6.39 - November 20, 2022\n" #define PNG_LIBPNG_VER_SONUM 16 #define PNG_LIBPNG_VER_DLLNUM 16 @@ -287,7 +287,7 @@ /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 -#define PNG_LIBPNG_VER_RELEASE 38 +#define PNG_LIBPNG_VER_RELEASE 39 /* This should be zero for a public release, or non-zero for a * development version. [Deprecated] @@ -318,7 +318,7 @@ * From version 1.0.1 it is: * XXYYZZ, where XX=major, YY=minor, ZZ=release */ -#define PNG_LIBPNG_VER 10638 /* 1.6.38 */ +#define PNG_LIBPNG_VER 10639 /* 1.6.39 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -428,7 +428,7 @@ extern "C" { /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char* png_libpng_version_1_6_38; +typedef char* png_libpng_version_1_6_39; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * diff --git a/thirdparty/libpng/pngconf.h b/thirdparty/libpng/pngconf.h index 89d28f83a0..fcb4b43069 100644 --- a/thirdparty/libpng/pngconf.h +++ b/thirdparty/libpng/pngconf.h @@ -1,7 +1,7 @@ /* pngconf.h - machine-configurable file for libpng * - * libpng version 1.6.38 + * libpng version 1.6.39 * * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson diff --git a/thirdparty/libpng/pnglibconf.h b/thirdparty/libpng/pnglibconf.h index 89d5b4c8ad..e5948c8ce1 100644 --- a/thirdparty/libpng/pnglibconf.h +++ b/thirdparty/libpng/pnglibconf.h @@ -1,6 +1,6 @@ /* pnglibconf.h - library build configuration */ -/* libpng version 1.6.38 */ +/* libpng version 1.6.39 */ /* Copyright (c) 2018-2022 Cosmin Truta */ /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */ diff --git a/thirdparty/libpng/pngpriv.h b/thirdparty/libpng/pngpriv.h index 2e426cf47d..b8a73b685d 100644 --- a/thirdparty/libpng/pngpriv.h +++ b/thirdparty/libpng/pngpriv.h @@ -1946,7 +1946,7 @@ PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, * the problem character.) This has not been tested within libpng. */ PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, - size_t size, int *statep, png_size_tp whereami),PNG_EMPTY); + size_t size, int *statep, size_t *whereami),PNG_EMPTY); /* This is the same but it checks a complete string and returns true * only if it just contains a floating point number. As of 1.5.4 this diff --git a/thirdparty/libpng/pngread.c b/thirdparty/libpng/pngread.c index 5ab9224038..96996ced5b 100644 --- a/thirdparty/libpng/pngread.c +++ b/thirdparty/libpng/pngread.c @@ -3762,13 +3762,13 @@ png_image_read_direct(png_voidp argument) mode = PNG_ALPHA_PNG; output_gamma = PNG_DEFAULT_sRGB; } - + if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) { mode = PNG_ALPHA_OPTIMIZED; change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA; } - + /* If 'do_local_background' is set check for the presence of gamma * correction; this is part of the work-round for the libpng bug * described above. diff --git a/thirdparty/libpng/pngrutil.c b/thirdparty/libpng/pngrutil.c index ca060dd15f..068ab193a3 100644 --- a/thirdparty/libpng/pngrutil.c +++ b/thirdparty/libpng/pngrutil.c @@ -3186,7 +3186,7 @@ png_check_chunk_length(png_const_structrp png_ptr, png_uint_32 length) { png_debug2(0," length = %lu, limit = %lu", (unsigned long)length,(unsigned long)limit); - png_chunk_error(png_ptr, "chunk data is too large"); + png_benign_error(png_ptr, "chunk data is too large"); } } diff --git a/thirdparty/libpng/pngwrite.c b/thirdparty/libpng/pngwrite.c index 06c45d16ab..4e58d776a9 100644 --- a/thirdparty/libpng/pngwrite.c +++ b/thirdparty/libpng/pngwrite.c @@ -75,10 +75,10 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, * library. If you have a new chunk to add, make a function to write it, * and put it in the correct location here. If you want the chunk written * after the image data, put it in png_write_end(). I strongly encourage - * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing - * the chunk, as that will keep the code from breaking if you want to just - * write a plain PNG file. If you have long comments, I suggest writing - * them in png_write_end(), and compressing them. + * you to supply a PNG_INFO_<chunk> flag, and check info_ptr->valid before + * writing the chunk, as that will keep the code from breaking if you want + * to just write a plain PNG file. If you have long comments, I suggest + * writing them in png_write_end(), and compressing them. */ void PNGAPI png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) diff --git a/thirdparty/libpng/pngwutil.c b/thirdparty/libpng/pngwutil.c index 16345e4c0b..01f0607c70 100644 --- a/thirdparty/libpng/pngwutil.c +++ b/thirdparty/libpng/pngwutil.c @@ -1,7 +1,7 @@ /* pngwutil.c - utilities to write a PNG file * - * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 2018-2022 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -1747,7 +1747,7 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, { png_uint_32 purpose_len; size_t units_len, total_len; - png_size_tp params_len; + size_t *params_len; png_byte buf[10]; png_byte new_purpose[80]; int i; @@ -1769,7 +1769,7 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, png_debug1(3, "pCAL units length = %d", (int)units_len); total_len = purpose_len + units_len + 10; - params_len = (png_size_tp)png_malloc(png_ptr, + params_len = (size_t *)png_malloc(png_ptr, (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (size_t)))); /* Find the length of each parameter, making sure we don't count the diff --git a/thirdparty/mbedtls/include/mbedtls/asn1write.h b/thirdparty/mbedtls/include/mbedtls/asn1write.h index 44afae0e56..5da7654bb4 100644 --- a/thirdparty/mbedtls/include/mbedtls/asn1write.h +++ b/thirdparty/mbedtls/include/mbedtls/asn1write.h @@ -90,7 +90,7 @@ int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, #if defined(MBEDTLS_BIGNUM_C) /** - * \brief Write a arbitrary-precision number (#MBEDTLS_ASN1_INTEGER) + * \brief Write an arbitrary-precision number (#MBEDTLS_ASN1_INTEGER) * in ASN.1 format. * * \note This function works backwards in data buffer. diff --git a/thirdparty/mbedtls/include/mbedtls/bignum.h b/thirdparty/mbedtls/include/mbedtls/bignum.h index dd594c512d..c61db82c6d 100644 --- a/thirdparty/mbedtls/include/mbedtls/bignum.h +++ b/thirdparty/mbedtls/include/mbedtls/bignum.h @@ -182,6 +182,20 @@ #endif /* !MBEDTLS_NO_UDBL_DIVISION */ #endif /* !MBEDTLS_HAVE_INT64 */ +/** \typedef mbedtls_mpi_uint + * \brief The type of machine digits in a bignum, called _limbs_. + * + * This is always an unsigned integer type with no padding bits. The size + * is platform-dependent. + */ + +/** \typedef mbedtls_mpi_sint + * \brief The signed type corresponding to #mbedtls_mpi_uint. + * + * This is always a signed integer type with no padding bits. The size + * is platform-dependent. + */ + #ifdef __cplusplus extern "C" { #endif @@ -191,9 +205,27 @@ extern "C" { */ typedef struct mbedtls_mpi { - int s; /*!< Sign: -1 if the mpi is negative, 1 otherwise */ - size_t n; /*!< total # of limbs */ - mbedtls_mpi_uint *p; /*!< pointer to limbs */ + /** Sign: -1 if the mpi is negative, 1 otherwise. + * + * The number 0 must be represented with `s = +1`. Although many library + * functions treat all-limbs-zero as equivalent to a valid representation + * of 0 regardless of the sign bit, there are exceptions, so bignum + * functions and external callers must always set \c s to +1 for the + * number zero. + * + * Note that this implies that calloc() or `... = {0}` does not create + * a valid MPI representation. You must call mbedtls_mpi_init(). + */ + int s; + + /** Total number of limbs in \c p. */ + size_t n; + + /** Pointer to limbs. + * + * This may be \c NULL if \c n is 0. + */ + mbedtls_mpi_uint *p; } mbedtls_mpi; @@ -280,7 +312,7 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ); * \param Y The MPI to be assigned from. This must point to an * initialized MPI. * \param assign The condition deciding whether to perform the - * assignment or not. Possible values: + * assignment or not. Must be either 0 or 1: * * \c 1: Perform the assignment `X = Y`. * * \c 0: Keep the original value of \p X. * @@ -291,6 +323,10 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ); * information through branch prediction and/or memory access * patterns analysis). * + * \warning If \p assign is neither 0 nor 1, the result of this function + * is indeterminate, and the resulting value in \p X might be + * neither its original value nor the value in \p Y. + * * \return \c 0 if successful. * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. * \return Another negative error code on other kinds of failure. @@ -303,24 +339,28 @@ int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned * * \param X The first MPI. This must be initialized. * \param Y The second MPI. This must be initialized. - * \param assign The condition deciding whether to perform - * the swap or not. Possible values: + * \param swap The condition deciding whether to perform + * the swap or not. Must be either 0 or 1: * * \c 1: Swap the values of \p X and \p Y. * * \c 0: Keep the original values of \p X and \p Y. * * \note This function is equivalent to - * if( assign ) mbedtls_mpi_swap( X, Y ); + * if( swap ) mbedtls_mpi_swap( X, Y ); * except that it avoids leaking any information about whether - * the assignment was done or not (the above code may leak + * the swap was done or not (the above code may leak * information through branch prediction and/or memory access * patterns analysis). * + * \warning If \p swap is neither 0 nor 1, the result of this function + * is indeterminate, and both \p X and \p Y might end up with + * values different to either of the original ones. + * * \return \c 0 if successful. * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. * \return Another negative error code on other kinds of failure. * */ -int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign ); +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap ); /** * \brief Store integer value in MPI. @@ -753,11 +793,11 @@ int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, * * \param Q The destination MPI for the quotient. * This may be \c NULL if the value of the - * quotient is not needed. + * quotient is not needed. This must not alias A or B. * \param R The destination MPI for the remainder value. * This may be \c NULL if the value of the - * remainder is not needed. - * \param A The dividend. This must point to an initialized MPi. + * remainder is not needed. This must not alias A or B. + * \param A The dividend. This must point to an initialized MPI. * \param B The divisor. This must point to an initialized MPI. * * \return \c 0 if successful. @@ -774,10 +814,10 @@ int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, * * \param Q The destination MPI for the quotient. * This may be \c NULL if the value of the - * quotient is not needed. + * quotient is not needed. This must not alias A. * \param R The destination MPI for the remainder value. * This may be \c NULL if the value of the - * remainder is not needed. + * remainder is not needed. This must not alias A. * \param A The dividend. This must point to an initialized MPi. * \param b The divisor. * @@ -832,6 +872,7 @@ int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, * \brief Perform a sliding-window exponentiation: X = A^E mod N * * \param X The destination MPI. This must point to an initialized MPI. + * This must not alias E or N. * \param A The base of the exponentiation. * This must point to an initialized MPI. * \param E The exponent MPI. This must point to an initialized MPI. diff --git a/thirdparty/mbedtls/include/mbedtls/bn_mul.h b/thirdparty/mbedtls/include/mbedtls/bn_mul.h index 31137cd4c2..a3fc363815 100644 --- a/thirdparty/mbedtls/include/mbedtls/bn_mul.h +++ b/thirdparty/mbedtls/include/mbedtls/bn_mul.h @@ -95,12 +95,28 @@ ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) /* + * GCC < 5.0 treated the x86 ebx (which is used for the GOT) as a + * fixed reserved register when building as PIC, leading to errors + * like: bn_mul.h:46:13: error: PIC register clobbered by 'ebx' in 'asm' + * + * This is fixed by an improved register allocator in GCC 5+. From the + * release notes: + * Register allocation improvements: Reuse of the PIC hard register, + * instead of using a fixed register, was implemented on x86/x86-64 + * targets. This improves generated PIC code performance as more hard + * registers can be used. + */ +#if defined(__GNUC__) && __GNUC__ < 5 && defined(__PIC__) +#define MULADDC_CANNOT_USE_EBX +#endif + +/* * Disable use of the i386 assembly code below if option -O0, to disable all * compiler optimisations, is passed, detected with __OPTIMIZE__ * This is done as the number of registers used in the assembly code doesn't * work with the -O0 option. */ -#if defined(__i386__) && defined(__OPTIMIZE__) +#if defined(__i386__) && defined(__OPTIMIZE__) && !defined(MULADDC_CANNOT_USE_EBX) #define MULADDC_INIT \ asm( \ @@ -563,10 +579,20 @@ "andi r7, r6, 0xffff \n\t" \ "bsrli r6, r6, 16 \n\t" -#define MULADDC_CORE \ +#if(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define MULADDC_LHUI \ + "lhui r9, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "lhui r8, r3, 0 \n\t" +#else +#define MULADDC_LHUI \ "lhui r8, r3, 0 \n\t" \ "addi r3, r3, 2 \n\t" \ - "lhui r9, r3, 0 \n\t" \ + "lhui r9, r3, 0 \n\t" +#endif + +#define MULADDC_CORE \ + MULADDC_LHUI \ "addi r3, r3, 2 \n\t" \ "mul r10, r9, r6 \n\t" \ "mul r11, r8, r7 \n\t" \ diff --git a/thirdparty/mbedtls/include/mbedtls/check_config.h b/thirdparty/mbedtls/include/mbedtls/check_config.h index be5c548e56..7ae1ff94db 100644 --- a/thirdparty/mbedtls/include/mbedtls/check_config.h +++ b/thirdparty/mbedtls/include/mbedtls/check_config.h @@ -525,6 +525,20 @@ #error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously" #endif +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_VSNPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_VSNPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_VSNPRINTF) ||\ + defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_VSNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_VSNPRINTF/MBEDTLS_PLATFORM_VSNPRINTF_ALT cannot be defined simultaneously" +#endif + #if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\ !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) #error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites" @@ -650,10 +664,9 @@ MBEDTLS_ECDSA_C requires MBEDTLS_PK_WRITE_C to be defined." #endif -#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PKCS1_V15) && \ - !defined(MBEDTLS_PK_WRITE_C) && defined(MBEDTLS_PSA_CRYPTO_C) -#error "MBEDTLS_PSA_CRYPTO_C, MBEDTLS_RSA_C and MBEDTLS_PKCS1_V15 defined, \ - but not all prerequisites" +#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_RSA_C) && \ + !( defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_PK_WRITE_C) ) +#error "MBEDTLS_PSA_CRYPTO_C with MBEDTLS_RSA_C requires MBEDTLS_PK_PARSE_C and MBEDTLS_PK_WRITE_C" #endif #if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ @@ -812,6 +825,11 @@ #error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites" #endif +#if defined(MBEDTLS_SSL_TICKET_C) && \ + !( defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) ) +#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites" +#endif + #if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \ !defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1) #error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites" @@ -926,6 +944,10 @@ #error "MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH defined, but not all prerequisites" #endif +#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) && !( defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) ) +#error "MBEDTLS_SSL_CONTEXT_SERIALIZATION defined, but not all prerequisites" +#endif + /* * Avoid warning from -pedantic. This is a convenient place for this * workaround since this is included by every single file before the diff --git a/thirdparty/mbedtls/include/mbedtls/config.h b/thirdparty/mbedtls/include/mbedtls/config.h index 1cd6eb6634..61db79362f 100644 --- a/thirdparty/mbedtls/include/mbedtls/config.h +++ b/thirdparty/mbedtls/include/mbedtls/config.h @@ -1329,7 +1329,7 @@ * Include backtrace information with each allocated block. * * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C - * GLIBC-compatible backtrace() an backtrace_symbols() support + * GLIBC-compatible backtrace() and backtrace_symbols() support * * Uncomment this macro to include backtrace information */ @@ -1620,6 +1620,8 @@ * saved after the handshake to allow for more efficient serialization, so if * you don't need this feature you'll save RAM by disabling it. * + * Requires: MBEDTLS_GCM_C or MBEDTLS_CCM_C or MBEDTLS_CHACHAPOLY_C + * * Comment to disable the context serialization APIs. */ #define MBEDTLS_SSL_CONTEXT_SERIALIZATION @@ -2425,7 +2427,7 @@ * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA * * \warning ARC4 is considered a weak cipher and its use constitutes a - * security risk. If possible, we recommend avoidng dependencies on + * security risk. If possible, we recommend avoiding dependencies on * it, and considering stronger ciphers instead. * */ @@ -3030,7 +3032,7 @@ * * \note See also our Knowledge Base article about porting to a new * environment: - * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * https://mbed-tls.readthedocs.io/en/latest/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS * * Module: library/net_sockets.c * @@ -3400,7 +3402,8 @@ * Module: library/ssl_ticket.c * Caller: * - * Requires: MBEDTLS_CIPHER_C + * Requires: MBEDTLS_CIPHER_C && + * ( MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C ) */ #define MBEDTLS_SSL_TICKET_C @@ -3456,7 +3459,7 @@ * contexts are not shared between threads. If you do intend to use contexts * between threads, you will need to enable this layer to prevent race * conditions. See also our Knowledge Base article about threading: - * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading + * https://mbed-tls.readthedocs.io/en/latest/kb/development/thread-safety-and-multi-threading * * Module: library/threading.c * @@ -3488,7 +3491,7 @@ * * \note See also our Knowledge Base article about porting to a new * environment: - * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * https://mbed-tls.readthedocs.io/en/latest/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS * * Module: library/timing.c * Caller: library/havege.c diff --git a/thirdparty/mbedtls/include/mbedtls/ecdsa.h b/thirdparty/mbedtls/include/mbedtls/ecdsa.h index 264a638bb5..118f7cedb1 100644 --- a/thirdparty/mbedtls/include/mbedtls/ecdsa.h +++ b/thirdparty/mbedtls/include/mbedtls/ecdsa.h @@ -309,10 +309,8 @@ int mbedtls_ecdsa_sign_det_ext( mbedtls_ecp_group *grp, mbedtls_mpi *r, * This must be initialized. * * \return \c 0 on success. - * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the signature - * is invalid. * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX - * error code on failure for any other reason. + * error code on failure. */ int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, const unsigned char *buf, size_t blen, diff --git a/thirdparty/mbedtls/include/mbedtls/md.h b/thirdparty/mbedtls/include/mbedtls/md.h index 84fafd2ac7..9cea40a89c 100644 --- a/thirdparty/mbedtls/include/mbedtls/md.h +++ b/thirdparty/mbedtls/include/mbedtls/md.h @@ -215,7 +215,7 @@ MBEDTLS_CHECK_RETURN_TYPICAL int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ); /** - * \brief This function clones the state of an message-digest + * \brief This function clones the state of a message-digest * context. * * \note You must call mbedtls_md_setup() on \c dst before calling diff --git a/thirdparty/mbedtls/include/mbedtls/platform.h b/thirdparty/mbedtls/include/mbedtls/platform.h index 06dd192eab..eaf5122bec 100644 --- a/thirdparty/mbedtls/include/mbedtls/platform.h +++ b/thirdparty/mbedtls/include/mbedtls/platform.h @@ -11,6 +11,13 @@ * implementations of these functions, or implementations specific to * their platform, which can be statically linked to the library or * dynamically configured at runtime. + * + * When all compilation options related to platform abstraction are + * disabled, this header just defines `mbedtls_xxx` function names + * as aliases to the standard `xxx` function. + * + * Most modules in the library and example programs are expected to + * include this header. */ /* * Copyright The Mbed TLS Contributors diff --git a/thirdparty/mbedtls/include/mbedtls/ripemd160.h b/thirdparty/mbedtls/include/mbedtls/ripemd160.h index 63270d1239..f890aefaee 100644 --- a/thirdparty/mbedtls/include/mbedtls/ripemd160.h +++ b/thirdparty/mbedtls/include/mbedtls/ripemd160.h @@ -74,7 +74,7 @@ void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx ); void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx ); /** - * \brief Clone (the state of) an RIPEMD-160 context + * \brief Clone (the state of) a RIPEMD-160 context * * \param dst The destination context * \param src The context to be cloned diff --git a/thirdparty/mbedtls/include/mbedtls/rsa.h b/thirdparty/mbedtls/include/mbedtls/rsa.h index 062df73aa0..8559f67bb9 100644 --- a/thirdparty/mbedtls/include/mbedtls/rsa.h +++ b/thirdparty/mbedtls/include/mbedtls/rsa.h @@ -491,7 +491,7 @@ int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ); * the current function does not have access to them, * and therefore cannot check them. See mbedtls_rsa_complete(). * If you want to check the consistency of the entire - * content of an PKCS1-encoded RSA private key, for example, you + * content of a PKCS1-encoded RSA private key, for example, you * should use mbedtls_rsa_validate_params() before setting * up the RSA context. * Additionally, if the implementation performs empirical checks, diff --git a/thirdparty/mbedtls/include/mbedtls/ssl.h b/thirdparty/mbedtls/include/mbedtls/ssl.h index 5064ec5689..aecac93f33 100644 --- a/thirdparty/mbedtls/include/mbedtls/ssl.h +++ b/thirdparty/mbedtls/include/mbedtls/ssl.h @@ -624,7 +624,7 @@ typedef int mbedtls_ssl_recv_t( void *ctx, * \param ctx Context for the receive callback (typically a file descriptor) * \param buf Buffer to write the received data to * \param len Length of the receive buffer - * \param timeout Maximum nomber of millisecondes to wait for data + * \param timeout Maximum number of milliseconds to wait for data * 0 means no timeout (potentially waiting forever) * * \return The callback must return the number of bytes received, @@ -652,7 +652,7 @@ typedef int mbedtls_ssl_recv_timeout_t( void *ctx, * for the associated \c mbedtls_ssl_get_timer_t callback to * return correct information. * - * \note If using a event-driven style of programming, an event must + * \note If using an event-driven style of programming, an event must * be generated when the final delay is passed. The event must * cause a call to \c mbedtls_ssl_handshake() with the proper * SSL context to be scheduled. Care must be taken to ensure @@ -2000,7 +2000,7 @@ int mbedtls_ssl_check_record( mbedtls_ssl_context const *ssl, * here, except if using an event-driven style. * * \note See also the "DTLS tutorial" article in our knowledge base. - * https://tls.mbed.org/kb/how-to/dtls-tutorial + * https://mbed-tls.readthedocs.io/en/latest/kb/how-to/dtls-tutorial */ void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, void *p_timer, diff --git a/thirdparty/mbedtls/include/mbedtls/ssl_internal.h b/thirdparty/mbedtls/include/mbedtls/ssl_internal.h index 46ade67b9c..77ad755477 100644 --- a/thirdparty/mbedtls/include/mbedtls/ssl_internal.h +++ b/thirdparty/mbedtls/include/mbedtls/ssl_internal.h @@ -782,7 +782,7 @@ struct mbedtls_ssl_transform #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) uint8_t in_cid_len; uint8_t out_cid_len; - unsigned char in_cid [ MBEDTLS_SSL_CID_OUT_LEN_MAX ]; + unsigned char in_cid [ MBEDTLS_SSL_CID_IN_LEN_MAX ]; unsigned char out_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ]; #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ diff --git a/thirdparty/mbedtls/include/mbedtls/version.h b/thirdparty/mbedtls/include/mbedtls/version.h index 44adcbfe03..b3b441d46b 100644 --- a/thirdparty/mbedtls/include/mbedtls/version.h +++ b/thirdparty/mbedtls/include/mbedtls/version.h @@ -38,16 +38,16 @@ */ #define MBEDTLS_VERSION_MAJOR 2 #define MBEDTLS_VERSION_MINOR 28 -#define MBEDTLS_VERSION_PATCH 1 +#define MBEDTLS_VERSION_PATCH 2 /** * The single version number has the following structure: * MMNNPP00 * Major version | Minor version | Patch version */ -#define MBEDTLS_VERSION_NUMBER 0x021C0100 -#define MBEDTLS_VERSION_STRING "2.28.1" -#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.28.1" +#define MBEDTLS_VERSION_NUMBER 0x021C0200 +#define MBEDTLS_VERSION_STRING "2.28.2" +#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.28.2" #if defined(MBEDTLS_VERSION_C) diff --git a/thirdparty/mbedtls/library/aes.c b/thirdparty/mbedtls/library/aes.c index 03d8b7ea61..74ea2672b0 100644 --- a/thirdparty/mbedtls/library/aes.c +++ b/thirdparty/mbedtls/library/aes.c @@ -40,14 +40,7 @@ #include "mbedtls/aesni.h" #endif -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_AES_ALT) @@ -1170,7 +1163,7 @@ int mbedtls_aes_crypt_xts( mbedtls_aes_xts_context *ctx, { /* We are on the last block in a decrypt operation that has * leftover bytes, so we need to use the next tweak for this block, - * and this tweak for the lefover bytes. Save the current tweak for + * and this tweak for the leftover bytes. Save the current tweak for * the leftovers and then update the current tweak for use on this, * the last full block. */ memcpy( prev_tweak, tweak, sizeof( tweak ) ); @@ -1770,7 +1763,8 @@ int mbedtls_aes_self_test( int verbose ) unsigned char key[32]; unsigned char buf[64]; const unsigned char *aes_tests; -#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) +#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_OFB) unsigned char iv[16]; #endif #if defined(MBEDTLS_CIPHER_MODE_CBC) diff --git a/thirdparty/mbedtls/library/arc4.c b/thirdparty/mbedtls/library/arc4.c index b34dc5e754..dcc13d539a 100644 --- a/thirdparty/mbedtls/library/arc4.c +++ b/thirdparty/mbedtls/library/arc4.c @@ -31,14 +31,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_ARC4_ALT) diff --git a/thirdparty/mbedtls/library/aria.c b/thirdparty/mbedtls/library/aria.c index bc05c4a319..5e52eea91e 100644 --- a/thirdparty/mbedtls/library/aria.c +++ b/thirdparty/mbedtls/library/aria.c @@ -31,24 +31,12 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_ARIA_ALT) #include "mbedtls/platform_util.h" -#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ - !defined(inline) && !defined(__cplusplus) -#define inline __inline -#endif - /* Parameter validation macros */ #define ARIA_VALIDATE_RET( cond ) \ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ARIA_BAD_INPUT_DATA ) @@ -895,15 +883,17 @@ static const uint8_t aria_test2_ctr_ct[3][48] = // CTR ciphertext }; #endif /* MBEDTLS_CIPHER_MODE_CFB */ -#define ARIA_SELF_TEST_IF_FAIL \ - { \ - if( verbose ) \ - mbedtls_printf( "failed\n" ); \ - goto exit; \ - } else { \ - if( verbose ) \ - mbedtls_printf( "passed\n" ); \ - } +#define ARIA_SELF_TEST_ASSERT( cond ) \ + do { \ + if( cond ) { \ + if( verbose ) \ + mbedtls_printf( "failed\n" ); \ + goto exit; \ + } else { \ + if( verbose ) \ + mbedtls_printf( "passed\n" ); \ + } \ + } while( 0 ) /* * Checkup routine @@ -937,16 +927,18 @@ int mbedtls_aria_self_test( int verbose ) mbedtls_printf( " ARIA-ECB-%d (enc): ", 128 + 64 * i ); mbedtls_aria_setkey_enc( &ctx, aria_test1_ecb_key, 128 + 64 * i ); mbedtls_aria_crypt_ecb( &ctx, aria_test1_ecb_pt, blk ); - if( memcmp( blk, aria_test1_ecb_ct[i], MBEDTLS_ARIA_BLOCKSIZE ) != 0 ) - ARIA_SELF_TEST_IF_FAIL; + ARIA_SELF_TEST_ASSERT( + memcmp( blk, aria_test1_ecb_ct[i], MBEDTLS_ARIA_BLOCKSIZE ) + != 0 ); /* test ECB decryption */ if( verbose ) mbedtls_printf( " ARIA-ECB-%d (dec): ", 128 + 64 * i ); mbedtls_aria_setkey_dec( &ctx, aria_test1_ecb_key, 128 + 64 * i ); mbedtls_aria_crypt_ecb( &ctx, aria_test1_ecb_ct[i], blk ); - if( memcmp( blk, aria_test1_ecb_pt, MBEDTLS_ARIA_BLOCKSIZE ) != 0 ) - ARIA_SELF_TEST_IF_FAIL; + ARIA_SELF_TEST_ASSERT( + memcmp( blk, aria_test1_ecb_pt, MBEDTLS_ARIA_BLOCKSIZE ) + != 0 ); } if( verbose ) mbedtls_printf( "\n" ); @@ -965,8 +957,8 @@ int mbedtls_aria_self_test( int verbose ) memset( buf, 0x55, sizeof( buf ) ); mbedtls_aria_crypt_cbc( &ctx, MBEDTLS_ARIA_ENCRYPT, 48, iv, aria_test2_pt, buf ); - if( memcmp( buf, aria_test2_cbc_ct[i], 48 ) != 0 ) - ARIA_SELF_TEST_IF_FAIL; + ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_cbc_ct[i], 48 ) + != 0 ); /* Test CBC decryption */ if( verbose ) @@ -976,8 +968,7 @@ int mbedtls_aria_self_test( int verbose ) memset( buf, 0xAA, sizeof( buf ) ); mbedtls_aria_crypt_cbc( &ctx, MBEDTLS_ARIA_DECRYPT, 48, iv, aria_test2_cbc_ct[i], buf ); - if( memcmp( buf, aria_test2_pt, 48 ) != 0 ) - ARIA_SELF_TEST_IF_FAIL; + ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_pt, 48 ) != 0 ); } if( verbose ) mbedtls_printf( "\n" ); @@ -996,8 +987,7 @@ int mbedtls_aria_self_test( int verbose ) j = 0; mbedtls_aria_crypt_cfb128( &ctx, MBEDTLS_ARIA_ENCRYPT, 48, &j, iv, aria_test2_pt, buf ); - if( memcmp( buf, aria_test2_cfb_ct[i], 48 ) != 0 ) - ARIA_SELF_TEST_IF_FAIL; + ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_cfb_ct[i], 48 ) != 0 ); /* Test CFB decryption */ if( verbose ) @@ -1008,8 +998,7 @@ int mbedtls_aria_self_test( int verbose ) j = 0; mbedtls_aria_crypt_cfb128( &ctx, MBEDTLS_ARIA_DECRYPT, 48, &j, iv, aria_test2_cfb_ct[i], buf ); - if( memcmp( buf, aria_test2_pt, 48 ) != 0 ) - ARIA_SELF_TEST_IF_FAIL; + ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_pt, 48 ) != 0 ); } if( verbose ) mbedtls_printf( "\n" ); @@ -1027,8 +1016,7 @@ int mbedtls_aria_self_test( int verbose ) j = 0; mbedtls_aria_crypt_ctr( &ctx, 48, &j, iv, blk, aria_test2_pt, buf ); - if( memcmp( buf, aria_test2_ctr_ct[i], 48 ) != 0 ) - ARIA_SELF_TEST_IF_FAIL; + ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_ctr_ct[i], 48 ) != 0 ); /* Test CTR decryption */ if( verbose ) @@ -1039,8 +1027,7 @@ int mbedtls_aria_self_test( int verbose ) j = 0; mbedtls_aria_crypt_ctr( &ctx, 48, &j, iv, blk, aria_test2_ctr_ct[i], buf ); - if( memcmp( buf, aria_test2_pt, 48 ) != 0 ) - ARIA_SELF_TEST_IF_FAIL; + ARIA_SELF_TEST_ASSERT( memcmp( buf, aria_test2_pt, 48 ) != 0 ); } if( verbose ) mbedtls_printf( "\n" ); diff --git a/thirdparty/mbedtls/library/asn1parse.c b/thirdparty/mbedtls/library/asn1parse.c index 22747d3ba4..bf97585289 100644 --- a/thirdparty/mbedtls/library/asn1parse.c +++ b/thirdparty/mbedtls/library/asn1parse.c @@ -31,13 +31,7 @@ #include "mbedtls/bignum.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif /* * ASN.1 DER decoding routines diff --git a/thirdparty/mbedtls/library/asn1write.c b/thirdparty/mbedtls/library/asn1write.c index afa26a6be9..4b59927cbb 100644 --- a/thirdparty/mbedtls/library/asn1write.c +++ b/thirdparty/mbedtls/library/asn1write.c @@ -26,13 +26,7 @@ #include <string.h> -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ) { @@ -78,9 +72,11 @@ int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len return( 4 ); } + int len_is_valid = 1; #if SIZE_MAX > 0xFFFFFFFF - if( len <= 0xFFFFFFFF ) + len_is_valid = ( len <= 0xFFFFFFFF ); #endif + if( len_is_valid ) { if( *p - start < 5 ) return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); @@ -93,9 +89,7 @@ int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len return( 5 ); } -#if SIZE_MAX > 0xFFFFFFFF return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); -#endif } int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ) diff --git a/thirdparty/mbedtls/library/base64.c b/thirdparty/mbedtls/library/base64.c index 83daa0bcc6..9021a041bb 100644 --- a/thirdparty/mbedtls/library/base64.c +++ b/thirdparty/mbedtls/library/base64.c @@ -28,12 +28,7 @@ #if defined(MBEDTLS_SELF_TEST) #include <string.h> -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ #endif /* MBEDTLS_SELF_TEST */ #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ diff --git a/thirdparty/mbedtls/library/bignum.c b/thirdparty/mbedtls/library/bignum.c index 32578e2c68..37193f55a8 100644 --- a/thirdparty/mbedtls/library/bignum.c +++ b/thirdparty/mbedtls/library/bignum.c @@ -46,15 +46,7 @@ #include <limits.h> #include <string.h> -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#include <stdlib.h> -#define mbedtls_printf printf -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #define MPI_VALIDATE_RET( cond ) \ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA ) @@ -270,6 +262,17 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) memcpy( Y, &T, sizeof( mbedtls_mpi ) ); } +static inline mbedtls_mpi_uint mpi_sint_abs( mbedtls_mpi_sint z ) +{ + if( z >= 0 ) + return( z ); + /* Take care to handle the most negative value (-2^(biL-1)) correctly. + * A naive -z would have undefined behavior. + * Write this in a way that makes popular compilers happy (GCC, Clang, + * MSVC). */ + return( (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z ); +} + /* * Set value from integer */ @@ -281,7 +284,7 @@ int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ) MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) ); memset( X->p, 0, X->n * ciL ); - X->p[0] = ( z < 0 ) ? -z : z; + X->p[0] = mpi_sint_abs( z ); X->s = ( z < 0 ) ? -1 : 1; cleanup: @@ -1101,7 +1104,7 @@ int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ) mbedtls_mpi_uint p[1]; MPI_VALIDATE_RET( X != NULL ); - *p = ( z < 0 ) ? -z : z; + *p = mpi_sint_abs( z ); Y.s = ( z < 0 ) ? -1 : 1; Y.n = 1; Y.p = p; @@ -1138,6 +1141,11 @@ int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi if( B->p[j - 1] != 0 ) break; + /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0 + * and B is 0 (of any size). */ + if( j == 0 ) + return( 0 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); o = B->p; p = X->p; c = 0; @@ -1257,10 +1265,12 @@ cleanup: return( ret ); } -/* - * Signed addition: X = A + B +/* Common function for signed addition and subtraction. + * Calculate A + B * flip_B where flip_B is 1 or -1. */ -int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +static int add_sub_mpi( mbedtls_mpi *X, + const mbedtls_mpi *A, const mbedtls_mpi *B, + int flip_B ) { int ret, s; MPI_VALIDATE_RET( X != NULL ); @@ -1268,16 +1278,21 @@ int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi MPI_VALIDATE_RET( B != NULL ); s = A->s; - if( A->s * B->s < 0 ) + if( A->s * B->s * flip_B < 0 ) { - if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) + int cmp = mbedtls_mpi_cmp_abs( A, B ); + if( cmp >= 0 ) { MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); - X->s = s; + /* If |A| = |B|, the result is 0 and we must set the sign bit + * to +1 regardless of which of A or B was negative. Otherwise, + * since |A| > |B|, the sign is the sign of A. */ + X->s = cmp == 0 ? 1 : s; } else { MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); + /* Since |A| < |B|, the sign is the opposite of A. */ X->s = -s; } } @@ -1293,38 +1308,19 @@ cleanup: } /* + * Signed addition: X = A + B + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + return( add_sub_mpi( X, A, B, 1 ) ); +} + +/* * Signed subtraction: X = A - B */ int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) { - int ret, s; - MPI_VALIDATE_RET( X != NULL ); - MPI_VALIDATE_RET( A != NULL ); - MPI_VALIDATE_RET( B != NULL ); - - s = A->s; - if( A->s * B->s > 0 ) - { - if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) - { - MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); - X->s = s; - } - else - { - MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); - X->s = -s; - } - } - else - { - MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); - X->s = s; - } - -cleanup: - - return( ret ); + return( add_sub_mpi( X, A, B, -1 ) ); } /* @@ -1337,7 +1333,7 @@ int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint MPI_VALIDATE_RET( X != NULL ); MPI_VALIDATE_RET( A != NULL ); - p[0] = ( b < 0 ) ? -b : b; + p[0] = mpi_sint_abs( b ); B.s = ( b < 0 ) ? -1 : 1; B.n = 1; B.p = p; @@ -1355,7 +1351,7 @@ int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint MPI_VALIDATE_RET( X != NULL ); MPI_VALIDATE_RET( A != NULL ); - p[0] = ( b < 0 ) ? -b : b; + p[0] = mpi_sint_abs( b ); B.s = ( b < 0 ) ? -1 : 1; B.n = 1; B.p = p; @@ -1776,7 +1772,7 @@ int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, mbedtls_mpi_uint p[1]; MPI_VALIDATE_RET( A != NULL ); - p[0] = ( b < 0 ) ? -b : b; + p[0] = mpi_sint_abs( b ); B.s = ( b < 0 ) ? -1 : 1; B.n = 1; B.p = p; @@ -2009,11 +2005,11 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi *prec_RR ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t wbits, wsize, one = 1; + size_t window_bitsize; size_t i, j, nblimbs; size_t bufsize, nbits; mbedtls_mpi_uint ei, mm, state; - mbedtls_mpi RR, T, W[ 1 << MBEDTLS_MPI_WINDOW_SIZE ], WW, Apos; + mbedtls_mpi RR, T, W[ (size_t) 1 << MBEDTLS_MPI_WINDOW_SIZE ], WW, Apos; int neg; MPI_VALIDATE_RET( X != NULL ); @@ -2042,21 +2038,59 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, i = mbedtls_mpi_bitlen( E ); - wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + window_bitsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; #if( MBEDTLS_MPI_WINDOW_SIZE < 6 ) - if( wsize > MBEDTLS_MPI_WINDOW_SIZE ) - wsize = MBEDTLS_MPI_WINDOW_SIZE; + if( window_bitsize > MBEDTLS_MPI_WINDOW_SIZE ) + window_bitsize = MBEDTLS_MPI_WINDOW_SIZE; #endif + const size_t w_table_used_size = (size_t) 1 << window_bitsize; + + /* + * This function is not constant-trace: its memory accesses depend on the + * exponent value. To defend against timing attacks, callers (such as RSA + * and DHM) should use exponent blinding. However this is not enough if the + * adversary can find the exponent in a single trace, so this function + * takes extra precautions against adversaries who can observe memory + * access patterns. + * + * This function performs a series of multiplications by table elements and + * squarings, and we want the prevent the adversary from finding out which + * table element was used, and from distinguishing between multiplications + * and squarings. Firstly, when multiplying by an element of the window + * W[i], we do a constant-trace table lookup to obfuscate i. This leaves + * squarings as having a different memory access patterns from other + * multiplications. So secondly, we put the accumulator X in the table as + * well, and also do a constant-trace table lookup to multiply by X. + * + * This way, all multiplications take the form of a lookup-and-multiply. + * The number of lookup-and-multiply operations inside each iteration of + * the main loop still depends on the bits of the exponent, but since the + * other operations in the loop don't have an easily recognizable memory + * trace, an adversary is unlikely to be able to observe the exact + * patterns. + * + * An adversary may still be able to recover the exponent if they can + * observe both memory accesses and branches. However, branch prediction + * exploitation typically requires many traces of execution over the same + * data, which is defeated by randomized blinding. + * + * To achieve this, we make a copy of X and we use the table entry in each + * calculation from this point on. + */ + const size_t x_index = 0; + mbedtls_mpi_init( &W[x_index] ); + mbedtls_mpi_copy( &W[x_index], X ); + j = N->n + 1; /* All W[i] and X must have at least N->n limbs for the mpi_montmul() * and mpi_montred() calls later. Here we ensure that W[1] and X are * large enough, and later we'll grow other W[i] to the same length. * They must not be shrunk midway through this function! */ - MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[x_index], j ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) ); @@ -2105,28 +2139,36 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, mpi_montmul( &W[1], &RR, N, mm, &T ); /* - * X = R^2 * R^-1 mod N = R mod N + * W[x_index] = R^2 * R^-1 mod N = R mod N */ - MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) ); - mpi_montred( X, N, mm, &T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[x_index], &RR ) ); + mpi_montred( &W[x_index], N, mm, &T ); + - if( wsize > 1 ) + if( window_bitsize > 1 ) { /* - * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + * W[i] = W[1] ^ i + * + * The first bit of the sliding window is always 1 and therefore we + * only need to store the second half of the table. + * + * (There are two special elements in the table: W[0] for the + * accumulator/result and W[1] for A in Montgomery form. Both of these + * are already set at this point.) */ - j = one << ( wsize - 1 ); + j = w_table_used_size / 2; MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) ); - for( i = 0; i < wsize - 1; i++ ) + for( i = 0; i < window_bitsize - 1; i++ ) mpi_montmul( &W[j], &W[j], N, mm, &T ); /* * W[i] = W[i - 1] * W[1] */ - for( i = j + 1; i < ( one << wsize ); i++ ) + for( i = j + 1; i < w_table_used_size; i++ ) { MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) ); @@ -2138,7 +2180,7 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, nblimbs = E->n; bufsize = 0; nbits = 0; - wbits = 0; + size_t exponent_bits_in_window = 0; state = 0; while( 1 ) @@ -2166,9 +2208,10 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, if( ei == 0 && state == 1 ) { /* - * out of window, square X + * out of window, square W[x_index] */ - mpi_montmul( X, X, N, mm, &T ); + MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, x_index ) ); + mpi_montmul( &W[x_index], &WW, N, mm, &T ); continue; } @@ -2178,25 +2221,30 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, state = 2; nbits++; - wbits |= ( ei << ( wsize - nbits ) ); + exponent_bits_in_window |= ( ei << ( window_bitsize - nbits ) ); - if( nbits == wsize ) + if( nbits == window_bitsize ) { /* - * X = X^wsize R^-1 mod N + * W[x_index] = W[x_index]^window_bitsize R^-1 mod N */ - for( i = 0; i < wsize; i++ ) - mpi_montmul( X, X, N, mm, &T ); + for( i = 0; i < window_bitsize; i++ ) + { + MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, + x_index ) ); + mpi_montmul( &W[x_index], &WW, N, mm, &T ); + } /* - * X = X * W[wbits] R^-1 mod N + * W[x_index] = W[x_index] * W[exponent_bits_in_window] R^-1 mod N */ - MBEDTLS_MPI_CHK( mpi_select( &WW, W, (size_t) 1 << wsize, wbits ) ); - mpi_montmul( X, &WW, N, mm, &T ); + MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, + exponent_bits_in_window ) ); + mpi_montmul( &W[x_index], &WW, N, mm, &T ); state--; nbits = 0; - wbits = 0; + exponent_bits_in_window = 0; } } @@ -2205,31 +2253,45 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, */ for( i = 0; i < nbits; i++ ) { - mpi_montmul( X, X, N, mm, &T ); + MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, x_index ) ); + mpi_montmul( &W[x_index], &WW, N, mm, &T ); - wbits <<= 1; + exponent_bits_in_window <<= 1; - if( ( wbits & ( one << wsize ) ) != 0 ) - mpi_montmul( X, &W[1], N, mm, &T ); + if( ( exponent_bits_in_window & ( (size_t) 1 << window_bitsize ) ) != 0 ) + { + MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, 1 ) ); + mpi_montmul( &W[x_index], &WW, N, mm, &T ); + } } /* - * X = A^E * R * R^-1 mod N = A^E mod N + * W[x_index] = A^E * R * R^-1 mod N = A^E mod N */ - mpi_montred( X, N, mm, &T ); + mpi_montred( &W[x_index], N, mm, &T ); if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 ) { - X->s = -1; - MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) ); + W[x_index].s = -1; + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &W[x_index], N, &W[x_index] ) ); } + /* + * Load the result in the output variable. + */ + mbedtls_mpi_copy( X, &W[x_index] ); + cleanup: - for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ ) + /* The first bit of the sliding window is always 1 and therefore the first + * half of the table was unused. */ + for( i = w_table_used_size/2; i < w_table_used_size; i++ ) mbedtls_mpi_free( &W[i] ); - mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos ); + mbedtls_mpi_free( &W[x_index] ); + mbedtls_mpi_free( &W[1] ); + mbedtls_mpi_free( &T ); + mbedtls_mpi_free( &Apos ); mbedtls_mpi_free( &WW ); if( prec_RR == NULL || prec_RR->p == NULL ) @@ -2862,7 +2924,7 @@ int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags, else { /* - * An necessary condition for Y and X = 2Y + 1 to be prime + * A necessary condition for Y and X = 2Y + 1 to be prime * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). * Make sure it is satisfied, while keeping X = 3 mod 4 */ diff --git a/thirdparty/mbedtls/library/camellia.c b/thirdparty/mbedtls/library/camellia.c index 29d730ab53..e90cd7f134 100644 --- a/thirdparty/mbedtls/library/camellia.c +++ b/thirdparty/mbedtls/library/camellia.c @@ -32,14 +32,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_CAMELLIA_ALT) diff --git a/thirdparty/mbedtls/library/ccm.c b/thirdparty/mbedtls/library/ccm.c index a21a37f55f..e0d43334f9 100644 --- a/thirdparty/mbedtls/library/ccm.c +++ b/thirdparty/mbedtls/library/ccm.c @@ -36,14 +36,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ #if !defined(MBEDTLS_CCM_ALT) diff --git a/thirdparty/mbedtls/library/chacha20.c b/thirdparty/mbedtls/library/chacha20.c index 658f046901..bd0701482c 100644 --- a/thirdparty/mbedtls/library/chacha20.c +++ b/thirdparty/mbedtls/library/chacha20.c @@ -32,22 +32,10 @@ #include <stddef.h> #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_CHACHA20_ALT) -#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ - !defined(inline) && !defined(__cplusplus) -#define inline __inline -#endif - /* Parameter validation macros */ #define CHACHA20_VALIDATE_RET( cond ) \ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA ) diff --git a/thirdparty/mbedtls/library/chachapoly.c b/thirdparty/mbedtls/library/chachapoly.c index dc75b2030a..4adf846857 100644 --- a/thirdparty/mbedtls/library/chachapoly.c +++ b/thirdparty/mbedtls/library/chachapoly.c @@ -28,14 +28,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_CHACHAPOLY_ALT) diff --git a/thirdparty/mbedtls/library/cipher.c b/thirdparty/mbedtls/library/cipher.c index f3b4bd29ce..67e3274587 100644 --- a/thirdparty/mbedtls/library/cipher.c +++ b/thirdparty/mbedtls/library/cipher.c @@ -63,12 +63,7 @@ #include "mbedtls/nist_kw.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #define CIPHER_VALIDATE_RET( cond ) \ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ) diff --git a/thirdparty/mbedtls/library/cipher_wrap.c b/thirdparty/mbedtls/library/cipher_wrap.c index 57eb3cb67f..c76bdcc0f8 100644 --- a/thirdparty/mbedtls/library/cipher_wrap.c +++ b/thirdparty/mbedtls/library/cipher_wrap.c @@ -76,13 +76,7 @@ #include <string.h> #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #if defined(MBEDTLS_GCM_C) /* shared by all GCM ciphers */ diff --git a/thirdparty/mbedtls/library/common.h b/thirdparty/mbedtls/library/common.h index c06472418d..1663d50226 100644 --- a/thirdparty/mbedtls/library/common.h +++ b/thirdparty/mbedtls/library/common.h @@ -29,8 +29,15 @@ #include "mbedtls/config.h" #endif +#include <stddef.h> #include <stdint.h> +/* Define `inline` on some non-C99-compliant compilers. */ +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + /** Helper to define a function as static except when building invasive tests. * * If a function is only used inside its own source file and should be @@ -52,6 +59,44 @@ #define MBEDTLS_STATIC_TESTABLE static #endif +/** Return an offset into a buffer. + * + * This is just the addition of an offset to a pointer, except that this + * function also accepts an offset of 0 into a buffer whose pointer is null. + * (`p + n` has undefined behavior when `p` is null, even when `n == 0`. + * A null pointer is a valid buffer pointer when the size is 0, for example + * as the result of `malloc(0)` on some platforms.) + * + * \param p Pointer to a buffer of at least n bytes. + * This may be \p NULL if \p n is zero. + * \param n An offset in bytes. + * \return Pointer to offset \p n in the buffer \p p. + * Note that this is only a valid pointer if the size of the + * buffer is at least \p n + 1. + */ +static inline unsigned char *mbedtls_buffer_offset( + unsigned char *p, size_t n ) +{ + return( p == NULL ? NULL : p + n ); +} + +/** Return an offset into a read-only buffer. + * + * Similar to mbedtls_buffer_offset(), but for const pointers. + * + * \param p Pointer to a buffer of at least n bytes. + * This may be \p NULL if \p n is zero. + * \param n An offset in bytes. + * \return Pointer to offset \p n in the buffer \p p. + * Note that this is only a valid pointer if the size of the + * buffer is at least \p n + 1. + */ +static inline const unsigned char *mbedtls_buffer_offset_const( + const unsigned char *p, size_t n ) +{ + return( p == NULL ? NULL : p + n ); +} + /** Byte Reading Macros * * Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th diff --git a/thirdparty/mbedtls/library/constant_time.c b/thirdparty/mbedtls/library/constant_time.c index e276d23ca0..2401b0434a 100644 --- a/thirdparty/mbedtls/library/constant_time.c +++ b/thirdparty/mbedtls/library/constant_time.c @@ -81,7 +81,7 @@ unsigned mbedtls_ct_uint_mask( unsigned value ) #endif } -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) size_t mbedtls_ct_size_mask( size_t value ) { @@ -97,7 +97,7 @@ size_t mbedtls_ct_size_mask( size_t value ) #endif } -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ +#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ #if defined(MBEDTLS_BIGNUM_C) @@ -272,7 +272,7 @@ unsigned mbedtls_ct_uint_if( unsigned condition, * \note if1 and if0 must be either 1 or -1, otherwise the result * is undefined. * - * \param condition Condition to test. + * \param condition Condition to test; must be either 0 or 1. * \param if1 The first sign; must be either +1 or -1. * \param if0 The second sign; must be either +1 or -1. * @@ -404,8 +404,7 @@ static void mbedtls_ct_mem_move_to_left( void *start, #endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) - +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) void mbedtls_ct_memcpy_if_eq( unsigned char *dest, const unsigned char *src, size_t len, @@ -527,7 +526,7 @@ cleanup: return( ret ); } -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ +#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ #if defined(MBEDTLS_BIGNUM_C) diff --git a/thirdparty/mbedtls/library/constant_time_internal.h b/thirdparty/mbedtls/library/constant_time_internal.h index a550b38fa5..ff2d0ff92c 100644 --- a/thirdparty/mbedtls/library/constant_time_internal.h +++ b/thirdparty/mbedtls/library/constant_time_internal.h @@ -32,7 +32,6 @@ #include <stddef.h> - /** Turn a value into a mask: * - if \p value == 0, return the all-bits 0 mask, aka 0 * - otherwise, return the all-bits 1 mask, aka (unsigned) -1 @@ -46,7 +45,7 @@ */ unsigned mbedtls_ct_uint_mask( unsigned value ); -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) /** Turn a value into a mask: * - if \p value == 0, return the all-bits 0 mask, aka 0 @@ -61,7 +60,7 @@ unsigned mbedtls_ct_uint_mask( unsigned value ); */ size_t mbedtls_ct_size_mask( size_t value ); -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ +#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ #if defined(MBEDTLS_BIGNUM_C) @@ -196,7 +195,7 @@ signed char mbedtls_ct_base64_dec_value( unsigned char c ); #endif /* MBEDTLS_BASE64_C */ -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) /** Conditional memcpy without branches. * @@ -292,7 +291,7 @@ int mbedtls_ct_hmac( mbedtls_md_context_t *ctx, size_t max_data_len, unsigned char *output ); -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ +#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) diff --git a/thirdparty/mbedtls/library/ctr_drbg.c b/thirdparty/mbedtls/library/ctr_drbg.c index a00d66ce87..ed31576a7b 100644 --- a/thirdparty/mbedtls/library/ctr_drbg.c +++ b/thirdparty/mbedtls/library/ctr_drbg.c @@ -36,14 +36,7 @@ #include <stdio.h> #endif -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ /* * CTR_DRBG context initialization diff --git a/thirdparty/mbedtls/library/debug.c b/thirdparty/mbedtls/library/debug.c index e1086008af..353b4bf07b 100644 --- a/thirdparty/mbedtls/library/debug.c +++ b/thirdparty/mbedtls/library/debug.c @@ -21,16 +21,7 @@ #if defined(MBEDTLS_DEBUG_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#define mbedtls_time_t time_t -#define mbedtls_snprintf snprintf -#define mbedtls_vsnprintf vsnprintf -#endif #include "mbedtls/debug.h" #include "mbedtls/error.h" @@ -39,11 +30,6 @@ #include <stdio.h> #include <string.h> -#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ - !defined(inline) && !defined(__cplusplus) -#define inline __inline -#endif - #define DEBUG_BUF_SIZE 512 static int debug_threshold = 0; diff --git a/thirdparty/mbedtls/library/des.c b/thirdparty/mbedtls/library/des.c index 91d22b5d90..65f5681cf1 100644 --- a/thirdparty/mbedtls/library/des.c +++ b/thirdparty/mbedtls/library/des.c @@ -33,14 +33,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_DES_ALT) diff --git a/thirdparty/mbedtls/library/dhm.c b/thirdparty/mbedtls/library/dhm.c index 88e148bb80..4d2e33e689 100644 --- a/thirdparty/mbedtls/library/dhm.c +++ b/thirdparty/mbedtls/library/dhm.c @@ -43,15 +43,7 @@ #include "mbedtls/asn1.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#include <stdio.h> -#define mbedtls_printf printf -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #if !defined(MBEDTLS_DHM_ALT) diff --git a/thirdparty/mbedtls/library/ecdh.c b/thirdparty/mbedtls/library/ecdh.c index 60c6e429de..724c938a71 100644 --- a/thirdparty/mbedtls/library/ecdh.c +++ b/thirdparty/mbedtls/library/ecdh.c @@ -77,10 +77,12 @@ static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp, { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - /* If multiplication is in progress, we already generated a privkey */ + int restarting = 0; #if defined(MBEDTLS_ECP_RESTARTABLE) - if( rs_ctx == NULL || rs_ctx->rsm == NULL ) + restarting = ( rs_ctx != NULL && rs_ctx->rsm != NULL ); #endif + /* If multiplication is in progress, we already generated a privkey */ + if( !restarting ) MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G, diff --git a/thirdparty/mbedtls/library/ecdsa.c b/thirdparty/mbedtls/library/ecdsa.c index 640eb24a26..4bae6a93fd 100644 --- a/thirdparty/mbedtls/library/ecdsa.c +++ b/thirdparty/mbedtls/library/ecdsa.c @@ -36,13 +36,7 @@ #include "mbedtls/hmac_drbg.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include "mbedtls/platform_util.h" #include "mbedtls/error.h" diff --git a/thirdparty/mbedtls/library/ecjpake.c b/thirdparty/mbedtls/library/ecjpake.c index 0b9bffb93e..fe0b9d93e9 100644 --- a/thirdparty/mbedtls/library/ecjpake.c +++ b/thirdparty/mbedtls/library/ecjpake.c @@ -794,12 +794,7 @@ cleanup: #if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif #if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ !defined(MBEDTLS_SHA256_C) diff --git a/thirdparty/mbedtls/library/ecp.c b/thirdparty/mbedtls/library/ecp.c index 890f364a08..ad19e05fb2 100644 --- a/thirdparty/mbedtls/library/ecp.c +++ b/thirdparty/mbedtls/library/ecp.c @@ -90,15 +90,7 @@ #define ECP_VALIDATE( cond ) \ MBEDTLS_INTERNAL_VALIDATE( cond ) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#include <stdio.h> -#define mbedtls_printf printf -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include "mbedtls/ecp_internal.h" @@ -112,11 +104,6 @@ #endif #endif /* MBEDTLS_ECP_NO_INTERNAL_RNG */ -#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ - !defined(inline) && !defined(__cplusplus) -#define inline __inline -#endif - #if defined(MBEDTLS_SELF_TEST) /* * Counts of point addition and doubling, and field multiplications. @@ -2056,9 +2043,13 @@ static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R i = d; MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, T_size, x[i] ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) ); + + int have_rng = 1; #if defined(MBEDTLS_ECP_NO_INTERNAL_RNG) - if( f_rng != 0 ) + if( f_rng == NULL ) + have_rng = 0; #endif + if( have_rng ) MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) ); } @@ -2192,9 +2183,12 @@ final_norm: * * Avoid the leak by randomizing coordinates before we normalize them. */ + int have_rng = 1; #if defined(MBEDTLS_ECP_NO_INTERNAL_RNG) - if( f_rng != 0 ) + if( f_rng == NULL ) + have_rng = 0; #endif + if( have_rng ) MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, RR, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, RR ) ); @@ -2403,12 +2397,14 @@ cleanup: mbedtls_free( T ); } - /* don't free R while in progress in case R == P */ + /* prevent caller from using invalid value */ + int should_free_R = ( ret != 0 ); #if defined(MBEDTLS_ECP_RESTARTABLE) - if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) + /* don't free R while in progress in case R == P */ + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + should_free_R = 0; #endif - /* prevent caller from using invalid value */ - if( ret != 0 ) + if( should_free_R ) mbedtls_ecp_point_free( R ); ECP_RS_LEAVE( rsm ); @@ -2596,13 +2592,16 @@ static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, MOD_ADD( RP.X ); /* Randomize coordinates of the starting point */ + int have_rng = 1; #if defined(MBEDTLS_ECP_NO_INTERNAL_RNG) - if( f_rng != NULL ) + if( f_rng == NULL ) + have_rng = 0; #endif + if( have_rng ) MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) ); /* Loop invariant: R = result so far, RP = R + P */ - i = mbedtls_mpi_bitlen( m ); /* one past the (zero-based) most significant bit */ + i = grp->nbits + 1; /* one past the (zero-based) required msb for private keys */ while( i-- > 0 ) { b = mbedtls_mpi_get_bit( m, i ); @@ -2631,9 +2630,12 @@ static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, * * Avoid the leak by randomizing coordinates before we normalize them. */ + have_rng = 1; #if defined(MBEDTLS_ECP_NO_INTERNAL_RNG) - if( f_rng != NULL ) + if( f_rng == NULL ) + have_rng = 0; #endif + if( have_rng ) MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, R, f_rng, p_rng ) ); MBEDTLS_MPI_CHK( ecp_normalize_mxz( grp, R ) ); @@ -2680,10 +2682,12 @@ int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); #endif /* MBEDTLS_ECP_INTERNAL_ALT */ + int restarting = 0; #if defined(MBEDTLS_ECP_RESTARTABLE) - /* skip argument check when restarting */ - if( rs_ctx == NULL || rs_ctx->rsm == NULL ) + restarting = ( rs_ctx != NULL && rs_ctx->rsm != NULL ); #endif + /* skip argument check when restarting */ + if( !restarting ) { /* check_privkey is free */ MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_CHK ); @@ -2797,14 +2801,17 @@ static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, if( mbedtls_mpi_cmp_int( m, 0 ) == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_set_zero( R ) ); } else if( mbedtls_mpi_cmp_int( m, 1 ) == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); } else if( mbedtls_mpi_cmp_int( m, -1 ) == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) ); MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); if( mbedtls_mpi_cmp_int( &R->Y, 0 ) != 0 ) MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &R->Y, &grp->P, &R->Y ) ); diff --git a/thirdparty/mbedtls/library/ecp_curves.c b/thirdparty/mbedtls/library/ecp_curves.c index 2199be6461..47761eef4e 100644 --- a/thirdparty/mbedtls/library/ecp_curves.c +++ b/thirdparty/mbedtls/library/ecp_curves.c @@ -38,11 +38,6 @@ #define ECP_VALIDATE( cond ) \ MBEDTLS_INTERNAL_VALIDATE( cond ) -#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ - !defined(inline) && !defined(__cplusplus) -#define inline __inline -#endif - #define ECP_MPI_INIT(s, n, p) {s, (n), (mbedtls_mpi_uint *)(p)} #define ECP_MPI_INIT_ARRAY(x) \ diff --git a/thirdparty/mbedtls/library/entropy.c b/thirdparty/mbedtls/library/entropy.c index 12fd3b9b5f..e3b337ff35 100644 --- a/thirdparty/mbedtls/library/entropy.c +++ b/thirdparty/mbedtls/library/entropy.c @@ -38,18 +38,9 @@ #include <stdio.h> #endif -#if defined(MBEDTLS_ENTROPY_NV_SEED) #include "mbedtls/platform.h" -#endif -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if defined(MBEDTLS_HAVEGE_C) #include "mbedtls/havege.h" diff --git a/thirdparty/mbedtls/library/entropy_poll.c b/thirdparty/mbedtls/library/entropy_poll.c index 40f23fd2a6..69ac29e4f7 100644 --- a/thirdparty/mbedtls/library/entropy_poll.c +++ b/thirdparty/mbedtls/library/entropy_poll.c @@ -38,9 +38,7 @@ #if defined(MBEDTLS_HAVEGE_C) #include "mbedtls/havege.h" #endif -#if defined(MBEDTLS_ENTROPY_NV_SEED) #include "mbedtls/platform.h" -#endif #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) diff --git a/thirdparty/mbedtls/library/error.c b/thirdparty/mbedtls/library/error.c index afad38904f..8573369a32 100644 --- a/thirdparty/mbedtls/library/error.c +++ b/thirdparty/mbedtls/library/error.c @@ -25,11 +25,7 @@ #if defined(MBEDTLS_ERROR_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#define mbedtls_snprintf snprintf -#endif #include <stdio.h> #include <string.h> @@ -961,7 +957,7 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) #else /* MBEDTLS_ERROR_C */ /* - * Provide an non-function in case MBEDTLS_ERROR_C is not defined + * Provide a dummy implementation when MBEDTLS_ERROR_C is not defined */ void mbedtls_strerror( int ret, char *buf, size_t buflen ) { diff --git a/thirdparty/mbedtls/library/gcm.c b/thirdparty/mbedtls/library/gcm.c index 43a5e1bec6..d0b73379a6 100644 --- a/thirdparty/mbedtls/library/gcm.c +++ b/thirdparty/mbedtls/library/gcm.c @@ -32,6 +32,7 @@ #if defined(MBEDTLS_GCM_C) #include "mbedtls/gcm.h" +#include "mbedtls/platform.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" @@ -41,15 +42,6 @@ #include "mbedtls/aesni.h" #endif -#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) -#include "mbedtls/aes.h" -#include "mbedtls/platform.h" -#if !defined(MBEDTLS_PLATFORM_C) -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ - #if !defined(MBEDTLS_GCM_ALT) /* Parameter validation macros */ diff --git a/thirdparty/mbedtls/library/hmac_drbg.c b/thirdparty/mbedtls/library/hmac_drbg.c index de9706885c..69272fa73d 100644 --- a/thirdparty/mbedtls/library/hmac_drbg.c +++ b/thirdparty/mbedtls/library/hmac_drbg.c @@ -37,14 +37,7 @@ #include <stdio.h> #endif -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_SELF_TEST */ -#endif /* MBEDTLS_PLATFORM_C */ /* * HMAC_DRBG context initialization diff --git a/thirdparty/mbedtls/library/md.c b/thirdparty/mbedtls/library/md.c index a10a835634..53a84b01c6 100644 --- a/thirdparty/mbedtls/library/md.c +++ b/thirdparty/mbedtls/library/md.c @@ -38,13 +38,7 @@ #include "mbedtls/sha256.h" #include "mbedtls/sha512.h" -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include <string.h> diff --git a/thirdparty/mbedtls/library/md2.c b/thirdparty/mbedtls/library/md2.c index 7264e30313..f8293a1df3 100644 --- a/thirdparty/mbedtls/library/md2.c +++ b/thirdparty/mbedtls/library/md2.c @@ -33,14 +33,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_MD2_ALT) diff --git a/thirdparty/mbedtls/library/md4.c b/thirdparty/mbedtls/library/md4.c index eaa679a0a6..a412213480 100644 --- a/thirdparty/mbedtls/library/md4.c +++ b/thirdparty/mbedtls/library/md4.c @@ -33,14 +33,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_MD4_ALT) diff --git a/thirdparty/mbedtls/library/md5.c b/thirdparty/mbedtls/library/md5.c index 4b53fcf367..e53bfe6306 100644 --- a/thirdparty/mbedtls/library/md5.c +++ b/thirdparty/mbedtls/library/md5.c @@ -32,14 +32,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_MD5_ALT) diff --git a/thirdparty/mbedtls/library/mps_reader.c b/thirdparty/mbedtls/library/mps_reader.c index 9af5073cc9..0c30a75d05 100644 --- a/thirdparty/mbedtls/library/mps_reader.c +++ b/thirdparty/mbedtls/library/mps_reader.c @@ -29,11 +29,6 @@ #include <string.h> -#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ - !defined(inline) && !defined(__cplusplus) -#define inline __inline -#endif - #if defined(MBEDTLS_MPS_ENABLE_TRACE) static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_READER; #endif /* MBEDTLS_MPS_ENABLE_TRACE */ @@ -535,7 +530,7 @@ int mbedtls_mps_reader_reclaim( mbedtls_mps_reader *rd, * of the accumulator. */ memmove( acc, acc + acc_backup_offset, acc_backup_len ); - /* Copy uncmmitted parts of the current fragment to the + /* Copy uncommitted parts of the current fragment to the * accumulator. */ memcpy( acc + acc_backup_len, frag + frag_backup_offset, frag_backup_len ); diff --git a/thirdparty/mbedtls/library/mps_trace.h b/thirdparty/mbedtls/library/mps_trace.h index 7c2360118a..820a1b66c2 100644 --- a/thirdparty/mbedtls/library/mps_trace.h +++ b/thirdparty/mbedtls/library/mps_trace.h @@ -30,13 +30,7 @@ #include "mps_common.h" #include "mps_trace.h" -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#define mbedtls_vsnprintf vsnprintf -#endif /* MBEDTLS_PLATFORM_C */ #if defined(MBEDTLS_MPS_ENABLE_TRACE) diff --git a/thirdparty/mbedtls/library/net_sockets.c b/thirdparty/mbedtls/library/net_sockets.c index 8c765e1c8c..b2cab503f2 100644 --- a/thirdparty/mbedtls/library/net_sockets.c +++ b/thirdparty/mbedtls/library/net_sockets.c @@ -37,11 +37,7 @@ #error "This module only works on Unix and Windows, see MBEDTLS_NET_C in config.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#endif #include "mbedtls/net_sockets.h" #include "mbedtls/error.h" diff --git a/thirdparty/mbedtls/library/nist_kw.c b/thirdparty/mbedtls/library/nist_kw.c index 1aea0b6345..495c23d06a 100644 --- a/thirdparty/mbedtls/library/nist_kw.c +++ b/thirdparty/mbedtls/library/nist_kw.c @@ -39,14 +39,7 @@ #include <stdint.h> #include <string.h> -#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ #if !defined(MBEDTLS_NIST_KW_ALT) diff --git a/thirdparty/mbedtls/library/oid.c b/thirdparty/mbedtls/library/oid.c index 19c8ac207c..53e5350eb3 100644 --- a/thirdparty/mbedtls/library/oid.c +++ b/thirdparty/mbedtls/library/oid.c @@ -30,11 +30,7 @@ #include <stdio.h> #include <string.h> -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#define mbedtls_snprintf snprintf -#endif /* * Macro to automatically add the size of #define'd OIDs diff --git a/thirdparty/mbedtls/library/pem.c b/thirdparty/mbedtls/library/pem.c index fcfde94799..cb1c82b3e4 100644 --- a/thirdparty/mbedtls/library/pem.c +++ b/thirdparty/mbedtls/library/pem.c @@ -32,13 +32,7 @@ #include <string.h> -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #if defined(MBEDTLS_PEM_PARSE_C) void mbedtls_pem_init( mbedtls_pem_context *ctx ) diff --git a/thirdparty/mbedtls/library/pk_wrap.c b/thirdparty/mbedtls/library/pk_wrap.c index 107e912ace..f35abf21a4 100644 --- a/thirdparty/mbedtls/library/pk_wrap.c +++ b/thirdparty/mbedtls/library/pk_wrap.c @@ -50,13 +50,7 @@ #include "mbedtls/asn1.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include <limits.h> #include <stdint.h> @@ -872,7 +866,7 @@ static void *pk_opaque_alloc_wrap( void ) { void *ctx = mbedtls_calloc( 1, sizeof( psa_key_id_t ) ); - /* no _init() function to call, an calloc() already zeroized */ + /* no _init() function to call, as calloc() already zeroized */ return( ctx ); } diff --git a/thirdparty/mbedtls/library/pkcs11.c b/thirdparty/mbedtls/library/pkcs11.c index 4deccf3f60..a7207cfc93 100644 --- a/thirdparty/mbedtls/library/pkcs11.c +++ b/thirdparty/mbedtls/library/pkcs11.c @@ -29,13 +29,7 @@ #include "mbedtls/oid.h" #include "mbedtls/x509_crt.h" -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include <string.h> diff --git a/thirdparty/mbedtls/library/pkcs5.c b/thirdparty/mbedtls/library/pkcs5.c index 2b014d91c8..f9d01371a7 100644 --- a/thirdparty/mbedtls/library/pkcs5.c +++ b/thirdparty/mbedtls/library/pkcs5.c @@ -42,12 +42,7 @@ #include <string.h> -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif #if defined(MBEDTLS_ASN1_PARSE_C) static int pkcs5_parse_pbkdf2_params( const mbedtls_asn1_buf *params, diff --git a/thirdparty/mbedtls/library/pkparse.c b/thirdparty/mbedtls/library/pkparse.c index ea5c6b69cb..6170d6d012 100644 --- a/thirdparty/mbedtls/library/pkparse.c +++ b/thirdparty/mbedtls/library/pkparse.c @@ -48,13 +48,7 @@ #include "mbedtls/pkcs12.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif /* Parameter validation macros based on platform_util.h */ #define PK_VALIDATE_RET( cond ) \ diff --git a/thirdparty/mbedtls/library/pkwrite.c b/thirdparty/mbedtls/library/pkwrite.c index 566153dd93..c1ce0e3f02 100644 --- a/thirdparty/mbedtls/library/pkwrite.c +++ b/thirdparty/mbedtls/library/pkwrite.c @@ -48,13 +48,7 @@ #include "psa/crypto.h" #include "mbedtls/psa_util.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif /* Parameter validation macros based on platform_util.h */ #define PK_VALIDATE_RET( cond ) \ diff --git a/thirdparty/mbedtls/library/poly1305.c b/thirdparty/mbedtls/library/poly1305.c index 7375a0c572..a1c5b19d8e 100644 --- a/thirdparty/mbedtls/library/poly1305.c +++ b/thirdparty/mbedtls/library/poly1305.c @@ -28,22 +28,10 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_POLY1305_ALT) -#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ - !defined(inline) && !defined(__cplusplus) -#define inline __inline -#endif - /* Parameter validation macros */ #define POLY1305_VALIDATE_RET( cond ) \ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA ) diff --git a/thirdparty/mbedtls/library/ripemd160.c b/thirdparty/mbedtls/library/ripemd160.c index aed7322cff..55e259e192 100644 --- a/thirdparty/mbedtls/library/ripemd160.c +++ b/thirdparty/mbedtls/library/ripemd160.c @@ -33,14 +33,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_RIPEMD160_ALT) diff --git a/thirdparty/mbedtls/library/rsa.c b/thirdparty/mbedtls/library/rsa.c index d1f6ddb177..9c39fa5d91 100644 --- a/thirdparty/mbedtls/library/rsa.c +++ b/thirdparty/mbedtls/library/rsa.c @@ -57,14 +57,7 @@ #include <stdlib.h> #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #if !defined(MBEDTLS_RSA_ALT) diff --git a/thirdparty/mbedtls/library/sha1.c b/thirdparty/mbedtls/library/sha1.c index 0a5edafaff..7f0c8757db 100644 --- a/thirdparty/mbedtls/library/sha1.c +++ b/thirdparty/mbedtls/library/sha1.c @@ -32,14 +32,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #define SHA1_VALIDATE_RET(cond) \ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA1_BAD_INPUT_DATA ) diff --git a/thirdparty/mbedtls/library/sha256.c b/thirdparty/mbedtls/library/sha256.c index db675efd1b..6f1306ee66 100644 --- a/thirdparty/mbedtls/library/sha256.c +++ b/thirdparty/mbedtls/library/sha256.c @@ -32,17 +32,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#include <stdlib.h> -#define mbedtls_printf printf -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #define SHA256_VALIDATE_RET(cond) \ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA256_BAD_INPUT_DATA ) diff --git a/thirdparty/mbedtls/library/sha512.c b/thirdparty/mbedtls/library/sha512.c index 02a135ca92..1a6872c8aa 100644 --- a/thirdparty/mbedtls/library/sha512.c +++ b/thirdparty/mbedtls/library/sha512.c @@ -38,17 +38,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#include <stdlib.h> -#define mbedtls_printf printf -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #define SHA512_VALIDATE_RET(cond) \ MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA512_BAD_INPUT_DATA ) @@ -428,9 +418,11 @@ int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, sha512_put_uint64_be( ctx->state[4], output, 32 ); sha512_put_uint64_be( ctx->state[5], output, 40 ); + int truncated = 0; #if !defined(MBEDTLS_SHA512_NO_SHA384) - if( ctx->is384 == 0 ) + truncated = ctx->is384; #endif + if( !truncated ) { sha512_put_uint64_be( ctx->state[6], output, 48 ); sha512_put_uint64_be( ctx->state[7], output, 56 ); diff --git a/thirdparty/mbedtls/library/ssl_cache.c b/thirdparty/mbedtls/library/ssl_cache.c index 32188cf3f6..7a600cad18 100644 --- a/thirdparty/mbedtls/library/ssl_cache.c +++ b/thirdparty/mbedtls/library/ssl_cache.c @@ -25,13 +25,7 @@ #if defined(MBEDTLS_SSL_CACHE_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include "mbedtls/ssl_cache.h" #include "mbedtls/ssl_internal.h" diff --git a/thirdparty/mbedtls/library/ssl_ciphersuites.c b/thirdparty/mbedtls/library/ssl_ciphersuites.c index ceec77efb0..2bc8a9bba0 100644 --- a/thirdparty/mbedtls/library/ssl_ciphersuites.c +++ b/thirdparty/mbedtls/library/ssl_ciphersuites.c @@ -23,11 +23,7 @@ #if defined(MBEDTLS_SSL_TLS_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#endif #include "mbedtls/ssl_ciphersuites.h" #include "mbedtls/ssl.h" diff --git a/thirdparty/mbedtls/library/ssl_cli.c b/thirdparty/mbedtls/library/ssl_cli.c index 72351c9757..b40ddb70b4 100644 --- a/thirdparty/mbedtls/library/ssl_cli.c +++ b/thirdparty/mbedtls/library/ssl_cli.c @@ -21,13 +21,7 @@ #if defined(MBEDTLS_SSL_CLI_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include "mbedtls/ssl.h" #include "mbedtls/ssl_internal.h" @@ -174,7 +168,7 @@ static int ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl, *olen = 0; - /* We're always including an TLS_EMPTY_RENEGOTIATION_INFO_SCSV in the + /* We're always including a TLS_EMPTY_RENEGOTIATION_INFO_SCSV in the * initial ClientHello, in which case also adding the renegotiation * info extension is NOT RECOMMENDED as per RFC 5746 Section 3.4. */ if( ssl->renego_status != MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) @@ -1004,9 +998,12 @@ static int ssl_write_client_hello( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_NO_RNG ); } + int renegotiating = 0; #if defined(MBEDTLS_SSL_RENEGOTIATION) - if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + renegotiating = 1; #endif + if( !renegotiating ) { ssl->major_ver = ssl->conf->min_major_ver; ssl->minor_ver = ssl->conf->min_minor_ver; @@ -1092,9 +1089,7 @@ static int ssl_write_client_hello( mbedtls_ssl_context *ssl ) * RFC 5077 section 3.4: "When presenting a ticket, the client MAY * generate and include a Session ID in the TLS ClientHello." */ -#if defined(MBEDTLS_SSL_RENEGOTIATION) - if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) -#endif + if( !renegotiating ) { if( ssl->session_negotiate->ticket != NULL && ssl->session_negotiate->ticket_len != 0 ) @@ -1209,9 +1204,7 @@ static int ssl_write_client_hello( mbedtls_ssl_context *ssl ) /* * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ -#if defined(MBEDTLS_SSL_RENEGOTIATION) - if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) -#endif + if( !renegotiating ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding EMPTY_RENEGOTIATION_INFO_SCSV" ) ); MBEDTLS_SSL_CHK_BUF_PTR( p, end, 2 ); @@ -2062,6 +2055,30 @@ static int ssl_parse_hello_verify_request( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_SSL_PROTO_DTLS */ +static int is_compression_bad( mbedtls_ssl_context *ssl, unsigned char comp ) +{ + int bad_comp = 0; + + /* Suppress warnings in some configurations */ + (void) ssl; +#if defined(MBEDTLS_ZLIB_SUPPORT) + /* See comments in ssl_write_client_hello() */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + comp != MBEDTLS_SSL_COMPRESS_NULL ) + bad_comp = 1; +#endif + + if( comp != MBEDTLS_SSL_COMPRESS_NULL && + comp != MBEDTLS_SSL_COMPRESS_DEFLATE ) + bad_comp = 1; +#else /* MBEDTLS_ZLIB_SUPPORT */ + if( comp != MBEDTLS_SSL_COMPRESS_NULL ) + bad_comp = 1; +#endif/* MBEDTLS_ZLIB_SUPPORT */ + return bad_comp; +} + MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_parse_server_hello( mbedtls_ssl_context *ssl ) { @@ -2070,9 +2087,6 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl ) size_t ext_len; unsigned char *buf, *ext; unsigned char comp; -#if defined(MBEDTLS_ZLIB_SUPPORT) - int accept_comp; -#endif #if defined(MBEDTLS_SSL_RENEGOTIATION) int renegotiation_info_seen = 0; #endif @@ -2241,20 +2255,7 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl ) */ comp = buf[37 + n]; -#if defined(MBEDTLS_ZLIB_SUPPORT) - /* See comments in ssl_write_client_hello() */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) - accept_comp = 0; - else -#endif - accept_comp = 1; - - if( comp != MBEDTLS_SSL_COMPRESS_NULL && - ( comp != MBEDTLS_SSL_COMPRESS_DEFLATE || accept_comp == 0 ) ) -#else /* MBEDTLS_ZLIB_SUPPORT */ - if( comp != MBEDTLS_SSL_COMPRESS_NULL ) -#endif/* MBEDTLS_ZLIB_SUPPORT */ + if( is_compression_bad( ssl, comp ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "server hello, bad compression: %d", comp ) ); @@ -2687,7 +2688,7 @@ static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl ) grp_id = ssl->handshake->ecdh_ctx.grp.id; #else grp_id = ssl->handshake->ecdh_ctx.grp_id; -#endif +#endif /* MBEDTLS_ECDH_LEGACY_CONTEXT */ curve_info = mbedtls_ecp_curve_info_from_grp_id( grp_id ); if( curve_info == NULL ) @@ -2700,11 +2701,12 @@ static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_ECP_C) if( mbedtls_ssl_check_curve( ssl, grp_id ) != 0 ) + return( -1 ); #else if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || ssl->handshake->ecdh_ctx.grp.nbits > 521 ) -#endif return( -1 ); +#endif /* MBEDTLS_ECP_C */ MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, MBEDTLS_DEBUG_ECDH_QP ); @@ -2858,8 +2860,8 @@ static int ssl_parse_server_psk_hint( mbedtls_ssl_context *ssl, } /* - * Note: we currently ignore the PKS identity hint, as we only allow one - * PSK to be provisionned on the client. This could be changed later if + * Note: we currently ignore the PSK identity hint, as we only allow one + * PSK to be provisioned on the client. This could be changed later if * someone needs that feature. */ *p += len; @@ -3452,23 +3454,23 @@ start_processing: #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) if( ssl->handshake->ecrs_enabled ) rs_ctx = &ssl->handshake->ecrs_ctx.pk; -#endif +#endif /* MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED */ if( ( ret = mbedtls_pk_verify_restartable( peer_pk, md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 ) { #if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) - if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) -#endif - mbedtls_ssl_send_alert_message( - ssl, - MBEDTLS_SSL_ALERT_LEVEL_FATAL, - MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR ); - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); -#if defined(MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED) if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) - ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; -#endif + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); + return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ); + } +#endif /* MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED */ + mbedtls_ssl_send_alert_message( + ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); return( ret ); } diff --git a/thirdparty/mbedtls/library/ssl_cookie.c b/thirdparty/mbedtls/library/ssl_cookie.c index 3781796b72..f12f28e849 100644 --- a/thirdparty/mbedtls/library/ssl_cookie.c +++ b/thirdparty/mbedtls/library/ssl_cookie.c @@ -25,12 +25,7 @@ #if defined(MBEDTLS_SSL_COOKIE_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include "mbedtls/ssl_cookie.h" #include "mbedtls/ssl_internal.h" diff --git a/thirdparty/mbedtls/library/ssl_msg.c b/thirdparty/mbedtls/library/ssl_msg.c index e47c538888..d7bebe04d6 100644 --- a/thirdparty/mbedtls/library/ssl_msg.c +++ b/thirdparty/mbedtls/library/ssl_msg.c @@ -30,13 +30,7 @@ #if defined(MBEDTLS_SSL_TLS_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include "mbedtls/ssl.h" #include "mbedtls/ssl_internal.h" @@ -441,9 +435,12 @@ static void ssl_extract_add_data_from_record( unsigned char* add_data, unsigned char *cur = add_data; + int is_tls13 = 0; #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) - if( minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 ) + if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + is_tls13 = 1; #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + if( !is_tls13 ) { ((void) minor_ver); memcpy( cur, rec->ctr, sizeof( rec->ctr ) ); @@ -1887,8 +1884,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) if( ssl->f_recv == NULL && ssl->f_recv_timeout == NULL ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " - "or mbedtls_ssl_set_bio()" ) ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " ) ); return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } @@ -2103,8 +2099,7 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) if( ssl->f_send == NULL ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " - "or mbedtls_ssl_set_bio()" ) ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " ) ); return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } @@ -3950,8 +3945,8 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, if( ssl_record_is_in_progress( ssl ) == 0 ) { + int dtls_have_buffered = 0; #if defined(MBEDTLS_SSL_PROTO_DTLS) - int have_buffered = 0; /* We only check for buffered messages if the * current datagram is fully consumed. */ @@ -3959,11 +3954,11 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, ssl_next_record_is_in_datagram( ssl ) == 0 ) { if( ssl_load_buffered_message( ssl ) == 0 ) - have_buffered = 1; + dtls_have_buffered = 1; } - if( have_buffered == 0 ) #endif /* MBEDTLS_SSL_PROTO_DTLS */ + if( dtls_have_buffered == 0 ) { ret = ssl_get_next_record( ssl ); if( ret == MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ) @@ -4037,7 +4032,7 @@ static int ssl_load_buffered_message( mbedtls_ssl_context *ssl ) if( hs == NULL ) return( -1 ); - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_messsage" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_message" ) ); if( ssl->state == MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC || ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC ) diff --git a/thirdparty/mbedtls/library/ssl_srv.c b/thirdparty/mbedtls/library/ssl_srv.c index 2efb13cc33..0563c0b590 100644 --- a/thirdparty/mbedtls/library/ssl_srv.c +++ b/thirdparty/mbedtls/library/ssl_srv.c @@ -21,13 +21,7 @@ #if defined(MBEDTLS_SSL_SRV_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include "mbedtls/ssl.h" #include "mbedtls/ssl_internal.h" @@ -1460,6 +1454,7 @@ static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); + int renegotiating = 0; #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) read_record_header: #endif @@ -1469,8 +1464,10 @@ read_record_header: * ClientHello, which doesn't use the same record layer format. */ #if defined(MBEDTLS_SSL_RENEGOTIATION) - if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + renegotiating = 1; #endif + if( !renegotiating ) { if( ( ret = mbedtls_ssl_fetch_input( ssl, 5 ) ) != 0 ) { @@ -1483,9 +1480,12 @@ read_record_header: buf = ssl->in_hdr; #if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) + int is_dtls = 0; #if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_STREAM ) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + is_dtls = 1; #endif + if( !is_dtls ) if( ( buf[0] & 0x80 ) != 0 ) return( ssl_parse_client_hello_v2( ssl ) ); #endif @@ -3903,8 +3903,14 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, size_t peer_pmssize ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_x509_crt *own_cert = mbedtls_ssl_own_cert( ssl ); + if( own_cert == NULL ) { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no local certificate" ) ); + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + mbedtls_pk_context *public_key = &own_cert->pk; mbedtls_pk_context *private_key = mbedtls_ssl_own_key( ssl ); - mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk; size_t len = mbedtls_pk_get_len( public_key ); #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) diff --git a/thirdparty/mbedtls/library/ssl_ticket.c b/thirdparty/mbedtls/library/ssl_ticket.c index e0126cc9d1..8a57789f10 100644 --- a/thirdparty/mbedtls/library/ssl_ticket.c +++ b/thirdparty/mbedtls/library/ssl_ticket.c @@ -21,13 +21,7 @@ #if defined(MBEDTLS_SSL_TICKET_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include "mbedtls/ssl_internal.h" #include "mbedtls/ssl_ticket.h" @@ -152,27 +146,45 @@ int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + int do_mbedtls_cipher_setup = 1; #if defined(MBEDTLS_USE_PSA_CRYPTO) ret = mbedtls_cipher_setup_psa( &ctx->keys[0].ctx, cipher_info, TICKET_AUTH_TAG_BYTES ); - if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) - return( ret ); - /* We don't yet expect to support all ciphers through PSA, - * so allow fallback to ordinary mbedtls_cipher_setup(). */ - if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) + + switch( ret ) + { + case 0: + do_mbedtls_cipher_setup = 0; + break; + case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE: + /* We don't yet expect to support all ciphers through PSA, + * so allow fallback to ordinary mbedtls_cipher_setup(). */ + do_mbedtls_cipher_setup = 1; + break; + default: + return( ret ); + } #endif /* MBEDTLS_USE_PSA_CRYPTO */ - if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 ) - return( ret ); + if( do_mbedtls_cipher_setup ) + if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) + != 0 ) + return( ret ); + do_mbedtls_cipher_setup = 1; #if defined(MBEDTLS_USE_PSA_CRYPTO) + do_mbedtls_cipher_setup = 0; + ret = mbedtls_cipher_setup_psa( &ctx->keys[1].ctx, cipher_info, TICKET_AUTH_TAG_BYTES ); if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) return( ret ); if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) + do_mbedtls_cipher_setup = 1; #endif /* MBEDTLS_USE_PSA_CRYPTO */ - if( ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 ) - return( ret ); + if( do_mbedtls_cipher_setup ) + if( ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) + != 0 ) + return( ret ); if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 || ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 ) diff --git a/thirdparty/mbedtls/library/ssl_tls.c b/thirdparty/mbedtls/library/ssl_tls.c index 7badec51ae..70196a4861 100644 --- a/thirdparty/mbedtls/library/ssl_tls.c +++ b/thirdparty/mbedtls/library/ssl_tls.c @@ -29,13 +29,7 @@ #if defined(MBEDTLS_SSL_TLS_C) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif #include "mbedtls/ssl.h" #include "mbedtls/ssl_internal.h" @@ -766,7 +760,9 @@ static int tls_prf_generic( mbedtls_md_type_t md_type, exit: mbedtls_md_free( &md_ctx ); - mbedtls_platform_zeroize( tmp, tmp_len ); + if ( tmp != NULL ) + mbedtls_platform_zeroize( tmp, tmp_len ); + mbedtls_platform_zeroize( h_i, sizeof( h_i ) ); mbedtls_free( tmp ); @@ -985,6 +981,7 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform, #if defined(MBEDTLS_USE_PSA_CRYPTO) int psa_fallthrough; #endif /* MBEDTLS_USE_PSA_CRYPTO */ + int do_mbedtls_cipher_setup; unsigned char keyblk[256]; unsigned char *key1; unsigned char *key2; @@ -1363,6 +1360,7 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform, } #endif + do_mbedtls_cipher_setup = 1; #if defined(MBEDTLS_USE_PSA_CRYPTO) /* Only use PSA-based ciphers for TLS-1.2. @@ -1398,15 +1396,18 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform, psa_fallthrough = 1; #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ - if( psa_fallthrough == 1 ) + if( psa_fallthrough == 0 ) + do_mbedtls_cipher_setup = 0; #endif /* MBEDTLS_USE_PSA_CRYPTO */ - if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, - cipher_info ) ) != 0 ) + if( do_mbedtls_cipher_setup && + ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, + cipher_info ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); goto end; } + do_mbedtls_cipher_setup = 1; #if defined(MBEDTLS_USE_PSA_CRYPTO) /* Only use PSA-based ciphers for TLS-1.2. * That's relevant at least for TLS-1.0, where @@ -1441,10 +1442,12 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform, psa_fallthrough = 1; #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ - if( psa_fallthrough == 1 ) + if( psa_fallthrough == 0 ) + do_mbedtls_cipher_setup = 0; #endif /* MBEDTLS_USE_PSA_CRYPTO */ - if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, - cipher_info ) ) != 0 ) + if( do_mbedtls_cipher_setup && + ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, + cipher_info ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); goto end; @@ -3411,7 +3414,7 @@ static void ssl_calc_finished_tls_sha384( sha512.state, sizeof( sha512.state ) ); #endif /* mbedtls_sha512_finish_ret's output parameter is declared as a - * 64-byte buffer, but sice we're using SHA-384, we know that the + * 64-byte buffer, but since we're using SHA-384, we know that the * output fits in 48 bytes. This is correct C, but GCC 11.1 warns * about it. */ @@ -4089,9 +4092,12 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) memset( ssl->out_buf, 0, out_buf_len ); + int clear_in_buf = 1; #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) - if( partial == 0 ) + if( partial != 0 ) + clear_in_buf = 0; #endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + if( clear_in_buf ) { ssl->in_left = 0; memset( ssl->in_buf, 0, in_buf_len ); @@ -4128,9 +4134,12 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) #endif #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + int free_cli_id = 1; #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) - if( partial == 0 ) + if( partial != 0 ) + free_cli_id = 0; #endif + if( free_cli_id ) { mbedtls_free( ssl->cli_id ); ssl->cli_id = NULL; @@ -4471,7 +4480,7 @@ static void ssl_conf_remove_psk( mbedtls_ssl_config *conf ) conf->psk_opaque = MBEDTLS_SVC_KEY_ID_INIT; } /* This and the following branch should never - * be taken simultaenously as we maintain the + * be taken simultaneously as we maintain the * invariant that raw and opaque PSKs are never * configured simultaneously. As a safeguard, * though, `else` is omitted here. */ @@ -6335,7 +6344,7 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_MSG( 1, ( "There is pending outgoing data" ) ); return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } - /* Protocol must be DLTS, not TLS */ + /* Protocol must be DTLS, not TLS */ if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "Only DTLS is supported" ) ); @@ -6510,24 +6519,41 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl, * Helper to get TLS 1.2 PRF from ciphersuite * (Duplicates bits of logic from ssl_set_handshake_prfs().) */ +#if defined(MBEDTLS_SHA256_C) || \ + (defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384)) typedef int (*tls_prf_fn)( const unsigned char *secret, size_t slen, const char *label, const unsigned char *random, size_t rlen, unsigned char *dstbuf, size_t dlen ); static tls_prf_fn ssl_tls12prf_from_cs( int ciphersuite_id ) { -#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384) const mbedtls_ssl_ciphersuite_t * const ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite_id ); + if( ciphersuite_info == NULL ) + return( NULL ); + +#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384) if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) return( tls_prf_sha384 ); -#else - (void) ciphersuite_id; + else +#endif +#if defined(MBEDTLS_SHA256_C) + { + if( ciphersuite_info->mac == MBEDTLS_MD_SHA256 ) + return( tls_prf_sha256 ); + } #endif - return( tls_prf_sha256 ); +#if !defined(MBEDTLS_SHA256_C) && \ + (!defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_SHA512_NO_SHA384)) + (void) ciphersuite_info; +#endif + return( NULL ); } +#endif /* MBEDTLS_SHA256_C || + (MBEDTLS_SHA512_C && !MBEDTLS_SHA512_NO_SHA384) */ + /* * Deserialize context, see mbedtls_ssl_context_save() for format. * @@ -6543,6 +6569,7 @@ static int ssl_context_load( mbedtls_ssl_context *ssl, const unsigned char * const end = buf + len; size_t session_len; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + tls_prf_fn prf_func = NULL; /* * The context should have been freshly setup or reset. @@ -6630,6 +6657,10 @@ static int ssl_context_load( mbedtls_ssl_context *ssl, ssl->transform_out = ssl->transform; ssl->transform_negotiate = NULL; + prf_func = ssl_tls12prf_from_cs( ssl->session->ciphersuite ); + if( prf_func == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + /* Read random bytes and populate structure */ if( (size_t)( end - p ) < sizeof( ssl->transform->randbytes ) ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); @@ -6648,7 +6679,7 @@ static int ssl_context_load( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_ZLIB_SUPPORT) ssl->session->compression, #endif - ssl_tls12prf_from_cs( ssl->session->ciphersuite ), + prf_func, p, /* currently pointing to randbytes */ MBEDTLS_SSL_MINOR_VERSION_3, /* (D)TLS 1.2 is forced */ ssl->conf->endpoint, @@ -6921,7 +6952,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) } /* - * Initialze mbedtls_ssl_config + * Initialize mbedtls_ssl_config */ void mbedtls_ssl_config_init( mbedtls_ssl_config *conf ) { diff --git a/thirdparty/mbedtls/library/ssl_tls13_keys.c b/thirdparty/mbedtls/library/ssl_tls13_keys.c index 3de6f03fb8..cc68773d3a 100644 --- a/thirdparty/mbedtls/library/ssl_tls13_keys.c +++ b/thirdparty/mbedtls/library/ssl_tls13_keys.c @@ -24,6 +24,7 @@ #include "mbedtls/hkdf.h" #include "mbedtls/ssl_internal.h" #include "ssl_tls13_keys.h" +#include "psa/crypto_sizes.h" #include <stdint.h> #include <string.h> @@ -31,6 +32,9 @@ #define MBEDTLS_SSL_TLS1_3_LABEL( name, string ) \ .name = string, +#define TLS1_3_EVOLVE_INPUT_SIZE ( PSA_HASH_MAX_SIZE > PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE ) ? \ + PSA_HASH_MAX_SIZE : PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE + struct mbedtls_ssl_tls1_3_labels_struct const mbedtls_ssl_tls1_3_labels = { /* This seems to work in C, despite the string literal being one @@ -292,8 +296,8 @@ int mbedtls_ssl_tls1_3_evolve_secret( { int ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; size_t hlen, ilen; - unsigned char tmp_secret[ MBEDTLS_MD_MAX_SIZE ] = { 0 }; - unsigned char tmp_input [ MBEDTLS_MD_MAX_SIZE ] = { 0 }; + unsigned char tmp_secret[ PSA_MAC_MAX_SIZE ] = { 0 }; + unsigned char tmp_input [ TLS1_3_EVOLVE_INPUT_SIZE ] = { 0 }; const mbedtls_md_info_t *md; md = mbedtls_md_info_from_type( hash_alg ); diff --git a/thirdparty/mbedtls/library/timing.c b/thirdparty/mbedtls/library/timing.c index 78bfa10cfb..151292e325 100644 --- a/thirdparty/mbedtls/library/timing.c +++ b/thirdparty/mbedtls/library/timing.c @@ -19,12 +19,7 @@ #include "common.h" -#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif #if defined(MBEDTLS_TIMING_C) @@ -269,7 +264,7 @@ static void TimerProc( void *TimerContext ) Sleep( alarmMs ); mbedtls_timing_alarmed = 1; /* _endthread will be called implicitly on return - * That ensures execution of thread funcition's epilogue */ + * That ensures execution of thread function's epilogue */ } void mbedtls_set_alarm( int seconds ) diff --git a/thirdparty/mbedtls/library/x509.c b/thirdparty/mbedtls/library/x509.c index 3997ebd1f3..54c8666d23 100644 --- a/thirdparty/mbedtls/library/x509.c +++ b/thirdparty/mbedtls/library/x509.c @@ -43,16 +43,7 @@ #include "mbedtls/pem.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#include <stdlib.h> -#define mbedtls_free free -#define mbedtls_calloc calloc -#define mbedtls_printf printf -#define mbedtls_snprintf snprintf -#endif #if defined(MBEDTLS_HAVE_TIME) #include "mbedtls/platform_time.h" @@ -198,7 +189,7 @@ static int x509_get_hash_alg( const mbedtls_x509_buf *alg, mbedtls_md_type_t *md * * RFC 4055 (which defines use of RSASSA-PSS in PKIX) states that the value * of trailerField MUST be 1, and PKCS#1 v2.2 doesn't even define any other - * option. Enfore this at parsing time. + * option. Enforce this at parsing time. */ int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, @@ -424,6 +415,11 @@ static int x509_get_attr_type_value( unsigned char **p, * For the general case we still use a flat list, but we mark elements of the * same set so that they are "merged" together in the functions that consume * this list, eg mbedtls_x509_dn_gets(). + * + * On success, this function may allocate a linked list starting at cur->next + * that must later be free'd by the caller using mbedtls_free(). In error + * cases, this function frees all allocated memory internally and the caller + * has no freeing responsibilities. */ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, mbedtls_x509_name *cur ) @@ -431,6 +427,8 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t set_len; const unsigned char *end_set; + mbedtls_x509_name *head = cur; + mbedtls_x509_name *prev, *allocated; /* don't use recursion, we'd risk stack overflow if not optimized */ while( 1 ) @@ -440,14 +438,17 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, */ if( ( ret = mbedtls_asn1_get_tag( p, end, &set_len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ) != 0 ) - return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_NAME, ret ) ); + { + ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_NAME, ret ); + goto error; + } end_set = *p + set_len; while( 1 ) { if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 ) - return( ret ); + goto error; if( *p == end_set ) break; @@ -458,7 +459,10 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); if( cur->next == NULL ) - return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + { + ret = MBEDTLS_ERR_X509_ALLOC_FAILED; + goto error; + } cur = cur->next; } @@ -472,10 +476,30 @@ int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); if( cur->next == NULL ) - return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + { + ret = MBEDTLS_ERR_X509_ALLOC_FAILED; + goto error; + } cur = cur->next; } + +error: + /* Skip the first element as we did not allocate it */ + allocated = head->next; + + while( allocated != NULL ) + { + prev = allocated; + allocated = allocated->next; + + mbedtls_platform_zeroize( prev, sizeof( *prev ) ); + mbedtls_free( prev ); + } + + mbedtls_platform_zeroize( head, sizeof( *head ) ); + + return( ret ); } static int x509_parse_int( unsigned char **p, size_t n, int *res ) diff --git a/thirdparty/mbedtls/library/x509_crl.c b/thirdparty/mbedtls/library/x509_crl.c index d2d8042029..b943a8d6da 100644 --- a/thirdparty/mbedtls/library/x509_crl.c +++ b/thirdparty/mbedtls/library/x509_crl.c @@ -1,5 +1,5 @@ /* - * X.509 Certidicate Revocation List (CRL) parsing + * X.509 Certificate Revocation List (CRL) parsing * * Copyright The Mbed TLS Contributors * SPDX-License-Identifier: Apache-2.0 @@ -42,15 +42,7 @@ #include "mbedtls/pem.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#include <stdio.h> -#define mbedtls_free free -#define mbedtls_calloc calloc -#define mbedtls_snprintf snprintf -#endif #if defined(MBEDTLS_HAVE_TIME) #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) diff --git a/thirdparty/mbedtls/library/x509_crt.c b/thirdparty/mbedtls/library/x509_crt.c index 96477e4c9d..4361f43ed0 100644 --- a/thirdparty/mbedtls/library/x509_crt.c +++ b/thirdparty/mbedtls/library/x509_crt.c @@ -49,15 +49,7 @@ #include "mbedtls/psa_util.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#include <stdlib.h> -#define mbedtls_free free -#define mbedtls_calloc calloc -#define mbedtls_snprintf snprintf -#endif #if defined(MBEDTLS_THREADING_C) #include "mbedtls/threading.h" @@ -90,6 +82,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> +#include <errno.h> #endif /* !_WIN32 || EFIX64 || EFI32 */ #endif @@ -1278,9 +1271,12 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, } } + int extensions_allowed = 1; #if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) - if( crt->version == 3 ) + if( crt->version != 3 ) + extensions_allowed = 0; #endif + if( extensions_allowed ) { ret = x509_get_crt_ext( &p, end, crt, cb, p_ctx ); if( ret != 0 ) @@ -1668,8 +1664,22 @@ cleanup: } else if( stat( entry_name, &sb ) == -1 ) { - ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; - goto cleanup; + if( errno == ENOENT ) + { + /* Broken symbolic link - ignore this entry. + stat(2) will return this error for either (a) a dangling + symlink or (b) a missing file. + Given that we have just obtained the filename from readdir, + assume that it does exist and therefore treat this as a + dangling symlink. */ + continue; + } + else + { + /* Some other file error; report the error. */ + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + goto cleanup; + } } if( !S_ISREG( sb.st_mode ) ) @@ -1798,6 +1808,7 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, const char *prefix ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i; size_t n = *size; char *p = *buf; const mbedtls_x509_sequence *cur = subject_alt_name; @@ -1850,18 +1861,11 @@ static int x509_info_subject_alt_name( char **buf, size_t *size, ret = mbedtls_snprintf( p, n, "\n%s hardware serial number : ", prefix ); MBEDTLS_X509_SAFE_SNPRINTF; - if( other_name->value.hardware_module_name.val.len >= n ) + for( i = 0; i < other_name->value.hardware_module_name.val.len; i++ ) { - *p = '\0'; - return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + ret = mbedtls_snprintf( p, n, "%02X", other_name->value.hardware_module_name.val.p[i] ); + MBEDTLS_X509_SAFE_SNPRINTF; } - - memcpy( p, other_name->value.hardware_module_name.val.p, - other_name->value.hardware_module_name.val.len ); - p += other_name->value.hardware_module_name.val.len; - - n -= other_name->value.hardware_module_name.val.len; - }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ } break; diff --git a/thirdparty/mbedtls/library/x509_csr.c b/thirdparty/mbedtls/library/x509_csr.c index e259410d07..1a22b77086 100644 --- a/thirdparty/mbedtls/library/x509_csr.c +++ b/thirdparty/mbedtls/library/x509_csr.c @@ -42,15 +42,7 @@ #include "mbedtls/pem.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#include <stdio.h> -#define mbedtls_free free -#define mbedtls_calloc calloc -#define mbedtls_snprintf snprintf -#endif #if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32) #include <stdio.h> diff --git a/thirdparty/mbedtls/library/x509write_csr.c b/thirdparty/mbedtls/library/x509write_csr.c index afda950341..707dd001f0 100644 --- a/thirdparty/mbedtls/library/x509write_csr.c +++ b/thirdparty/mbedtls/library/x509write_csr.c @@ -44,13 +44,7 @@ #include "mbedtls/pem.h" #endif -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdlib.h> -#define mbedtls_calloc calloc -#define mbedtls_free free -#endif void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ) { diff --git a/thirdparty/mbedtls/library/xtea.c b/thirdparty/mbedtls/library/xtea.c index 77f6cb6f67..28e6972aa8 100644 --- a/thirdparty/mbedtls/library/xtea.c +++ b/thirdparty/mbedtls/library/xtea.c @@ -1,5 +1,5 @@ /* - * An 32-bit implementation of the XTEA algorithm + * A 32-bit implementation of the XTEA algorithm * * Copyright The Mbed TLS Contributors * SPDX-License-Identifier: Apache-2.0 @@ -26,14 +26,7 @@ #include <string.h> -#if defined(MBEDTLS_SELF_TEST) -#if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" -#else -#include <stdio.h> -#define mbedtls_printf printf -#endif /* MBEDTLS_PLATFORM_C */ -#endif /* MBEDTLS_SELF_TEST */ #if !defined(MBEDTLS_XTEA_ALT) diff --git a/thirdparty/mbedtls/patches/1453.diff b/thirdparty/mbedtls/patches/1453.diff index b1c9c43ed2..4a7ca1570b 100644 --- a/thirdparty/mbedtls/patches/1453.diff +++ b/thirdparty/mbedtls/patches/1453.diff @@ -1,8 +1,8 @@ -diff --git a/library/entropy_poll.c b/library/entropy_poll.c -index 4556f88a5..ba56b70f7 100644 ---- a/library/entropy_poll.c -+++ b/library/entropy_poll.c -@@ -61,28 +61,43 @@ +diff --git a/thirdparty/mbedtls/library/entropy_poll.c b/thirdparty/mbedtls/library/entropy_poll.c +index a858c1892b..69ac29e4f7 100644 +--- a/thirdparty/mbedtls/library/entropy_poll.c ++++ b/thirdparty/mbedtls/library/entropy_poll.c +@@ -54,28 +54,43 @@ #define _WIN32_WINNT 0x0400 #endif #include <windows.h> @@ -53,12 +53,12 @@ index 4556f88a5..ba56b70f7 100644 *olen = len; return( 0 ); -diff --git a/library/x509_crt.c b/library/x509_crt.c -index 76558342e..35a134950 100644 ---- a/library/x509_crt.c -+++ b/library/x509_crt.c -@@ -65,6 +65,19 @@ - +diff --git a/thirdparty/mbedtls/library/x509_crt.c b/thirdparty/mbedtls/library/x509_crt.c +index def1414eca..4361f43ed0 100644 +--- a/thirdparty/mbedtls/library/x509_crt.c ++++ b/thirdparty/mbedtls/library/x509_crt.c +@@ -58,6 +58,19 @@ + #if defined(MBEDTLS_HAVE_TIME) #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) #include <windows.h> +#if defined(_MSC_VER) && _MSC_VER <= 1600 @@ -77,7 +77,7 @@ index 76558342e..35a134950 100644 #else #include <time.h> #endif -@@ -1278,6 +1291,7 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +@@ -1549,6 +1562,7 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) char filename[MAX_PATH]; char *p; size_t len = strlen( path ); @@ -85,7 +85,7 @@ index 76558342e..35a134950 100644 WIN32_FIND_DATAW file_data; HANDLE hFind; -@@ -1292,7 +1306,18 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +@@ -1563,7 +1577,18 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) p = filename + len; filename[len++] = '*'; @@ -105,7 +105,7 @@ index 76558342e..35a134950 100644 MAX_PATH - 3 ); if( w_ret == 0 ) return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); -@@ -1309,8 +1334,11 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +@@ -1580,8 +1605,11 @@ int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) continue; diff --git a/thirdparty/mbedtls/patches/windows-arm64-hardclock.diff b/thirdparty/mbedtls/patches/windows-arm64-hardclock.diff new file mode 100644 index 0000000000..c7c5a7e282 --- /dev/null +++ b/thirdparty/mbedtls/patches/windows-arm64-hardclock.diff @@ -0,0 +1,16 @@ +diff --git a/thirdparty/mbedtls/library/timing.c b/thirdparty/mbedtls/library/timing.c +index 6c14a4fd01..151292e325 100644 +--- a/thirdparty/mbedtls/library/timing.c ++++ b/thirdparty/mbedtls/library/timing.c +@@ -190,8 +190,10 @@ unsigned long mbedtls_timing_hardclock( void ) + #endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __ia64__ */ + +-#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ ++// -- GODOT start -- ++#if !defined(HAVE_HARDCLOCK) && defined(_WIN32) && \ + !defined(EFIX64) && !defined(EFI32) ++// -- GODOT end -- + + #define HAVE_HARDCLOCK + |