diff options
21 files changed, 290 insertions, 227 deletions
diff --git a/core/input/input_builders.py b/core/input/input_builders.py index a7729c9af2..76e199e0ff 100644 --- a/core/input/input_builders.py +++ b/core/input/input_builders.py @@ -45,7 +45,7 @@ def make_default_controller_mappings(target, source, env): platform_mappings[current_platform][guid] = line platform_variables = { - "Linux": "#if X11_ENABLED", + "Linux": "#if LINUXBSD_ENABLED", "Windows": "#ifdef WINDOWS_ENABLED", "Mac OS X": "#ifdef MACOS_ENABLED", "Android": "#if defined(__ANDROID__)", diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 557060c907..a162f46103 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -189,7 +189,7 @@ void DirAccessUnix::list_dir_end() { _cisdir = false; } -#if defined(HAVE_MNTENT) && defined(X11_ENABLED) +#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED) static bool _filter_drive(struct mntent *mnt) { // Ignore devices that don't point to /dev if (strncmp(mnt->mnt_fsname, "/dev", 4) != 0) { @@ -213,7 +213,7 @@ static void _get_drives(List<String> *list) { // Add root. list->push_back("/"); -#if defined(HAVE_MNTENT) && defined(X11_ENABLED) +#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED) // Check /etc/mtab for the list of mounted partitions. FILE *mtab = setmntent("/etc/mtab", "r"); if (mtab) { diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index f1fd1d5a03..ad6d41e10c 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -218,7 +218,8 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ Vector<Vector3> normals; Vector<Vector2> uvs; Vector<Color> colors; - String name; + const String default_name = "Mesh"; + String name = default_name; HashMap<String, HashMap<String, Ref<StandardMaterial3D>>> material_map; @@ -395,9 +396,12 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ if (l.begins_with("o ") || f->eof_reached()) { if (!p_single_mesh) { - mesh->set_name(name); - r_meshes.push_back(mesh); - mesh.instantiate(); + if (mesh->get_surface_count() > 0) { + mesh->set_name(name); + r_meshes.push_back(mesh); + mesh.instantiate(); + } + name = default_name; current_group = ""; current_material = ""; } @@ -460,6 +464,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, co for (const Ref<Mesh> &m : meshes) { Ref<ImporterMesh> mesh; mesh.instantiate(); + mesh->set_name(m->get_name()); for (int i = 0; i < m->get_surface_count(); i++) { mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i)); } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 1b488d560c..3d74445ff2 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2910,8 +2910,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base_set_class(GDScriptParser::Ide p_identifier->set_datatype(p_identifier_datatype); Error err = OK; - GDScript *scr = GDScriptCache::get_full_script(p_identifier_datatype.script_path, err).ptr(); - ERR_FAIL_COND_MSG(err != OK, "Error while getting full script."); + GDScript *scr = GDScriptCache::get_shallow_script(p_identifier_datatype.script_path, err).ptr(); + ERR_FAIL_COND_MSG(err != OK, vformat(R"(Error while getting cache for script "%s".)", p_identifier_datatype.script_path)); scr = scr->find_class(p_identifier_datatype.class_type->fqcn); p_identifier->reduced_value = scr; p_identifier->is_constant = true; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 77c6690d20..d63a1b4536 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -213,7 +213,7 @@ static bool _have_exact_arguments(const MethodBind *p_method, const Vector<GDScr } GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) { - if (p_expression->is_constant && !p_expression->get_datatype().is_meta_type) { + if (p_expression->is_constant && !(p_expression->get_datatype().is_meta_type && p_expression->get_datatype().kind == GDScriptParser::DataType::CLASS)) { return codegen.add_constant(p_expression->reduced_value); } diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 397c43b14b..3fc0924b4c 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1275,6 +1275,14 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context } r_result.insert(option.display, option); } + + // Global classes + List<StringName> global_classes; + ScriptServer::get_global_class_list(&global_classes); + for (const StringName &E : global_classes) { + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE); + r_result.insert(option.display, option); + } } static GDScriptCompletionIdentifier _type_from_variant(const Variant &p_value) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 97d5c1d8b2..f5d3306376 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -540,43 +540,28 @@ void GDScriptParser::parse_program() { head = alloc_node<ClassNode>(); head->fqcn = script_path; current_class = head; + bool can_have_class_or_extends = true; - // If we happen to parse an annotation before extends or class_name keywords, track it. - // @tool is allowed, but others should fail. - AnnotationNode *premature_annotation = nullptr; - - if (match(GDScriptTokenizer::Token::ANNOTATION)) { - // Check for @tool, script-level, or standalone annotation. + while (match(GDScriptTokenizer::Token::ANNOTATION)) { AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL); if (annotation != nullptr) { - if (annotation->name == SNAME("@tool")) { - // TODO: don't allow @tool anywhere else. (Should all script annotations be the first thing?). - _is_tool = true; - if (previous.type != GDScriptTokenizer::Token::NEWLINE) { - push_error(R"(Expected newline after "@tool" annotation.)"); - } - // @tool annotation has no specific target. - annotation->apply(this, nullptr); - } else if (annotation->applies_to(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE)) { - premature_annotation = annotation; - if (previous.type != GDScriptTokenizer::Token::NEWLINE) { - push_error(R"(Expected newline after a standalone annotation.)"); - } + if (annotation->applies_to(AnnotationInfo::SCRIPT)) { annotation->apply(this, head); } else { - premature_annotation = annotation; annotation_stack.push_back(annotation); + // This annotation must appear after script-level annotations + // and class_name/extends (ex: could be @onready or @export), + // so we stop looking for script-level stuff. + can_have_class_or_extends = false; + break; } } } - for (bool should_break = false; !should_break;) { + while (can_have_class_or_extends) { // Order here doesn't matter, but there should be only one of each at most. switch (current.type) { case GDScriptTokenizer::Token::CLASS_NAME: - if (premature_annotation != nullptr) { - push_error(R"("class_name" should be used before annotations (except @tool).)"); - } advance(); if (head->identifier != nullptr) { push_error(R"("class_name" can only be used once.)"); @@ -585,9 +570,6 @@ void GDScriptParser::parse_program() { } break; case GDScriptTokenizer::Token::EXTENDS: - if (premature_annotation != nullptr) { - push_error(R"("extends" should be used before annotations (except @tool).)"); - } advance(); if (head->extends_used) { push_error(R"("extends" can only be used once.)"); @@ -597,7 +579,8 @@ void GDScriptParser::parse_program() { } break; default: - should_break = true; + // No tokens are allowed between script annotations and class/extends. + can_have_class_or_extends = false; break; } @@ -606,21 +589,6 @@ void GDScriptParser::parse_program() { } } - if (match(GDScriptTokenizer::Token::ANNOTATION)) { - // Check for a script-level, or standalone annotation. - AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL); - if (annotation != nullptr) { - if (annotation->applies_to(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE)) { - if (previous.type != GDScriptTokenizer::Token::NEWLINE) { - push_error(R"(Expected newline after a standalone annotation.)"); - } - annotation->apply(this, head); - } else { - annotation_stack.push_back(annotation); - } - } - } - parse_class_body(true); complete_extents(head); diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd index 179e454073..0085b3f367 100644 --- a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd +++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd @@ -1,6 +1,6 @@ -# Error here. `class_name` should be used *before* annotations, not after (except @tool). -@icon("res://path/to/optional/icon.svg") +# Error here. Annotations should be used before `class_name`, not after. class_name HelloWorld +@icon("res://path/to/optional/icon.svg") func test(): pass diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out index 02b33c8692..a598ff8424 100644 --- a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out +++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out @@ -1,2 +1,2 @@ GDTEST_PARSER_ERROR -"class_name" should be used before annotations (except @tool). +Annotation "@icon" is not allowed in this level. diff --git a/modules/gdscript/tests/scripts/parser/features/class_name.gd b/modules/gdscript/tests/scripts/parser/features/class_name.gd index 8bd188e247..19009e433d 100644 --- a/modules/gdscript/tests/scripts/parser/features/class_name.gd +++ b/modules/gdscript/tests/scripts/parser/features/class_name.gd @@ -1,5 +1,5 @@ -class_name HelloWorld @icon("res://path/to/optional/icon.svg") +class_name HelloWorld func test(): pass diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 19f7c54847..b57317e1d0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -816,26 +816,26 @@ namespace Godot public Basis(Vector3 axis, real_t angle) { Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); - real_t cosine = Mathf.Cos(angle); - Row0.x = axisSq.x + cosine * (1.0f - axisSq.x); - Row1.y = axisSq.y + cosine * (1.0f - axisSq.y); - Row2.z = axisSq.z + cosine * (1.0f - axisSq.z); + (real_t sin, real_t cos) = Mathf.SinCos(angle); - real_t sine = Mathf.Sin(angle); - real_t t = 1.0f - cosine; + Row0.x = axisSq.x + cos * (1.0f - axisSq.x); + Row1.y = axisSq.y + cos * (1.0f - axisSq.y); + Row2.z = axisSq.z + cos * (1.0f - axisSq.z); + + real_t t = 1.0f - cos; real_t xyzt = axis.x * axis.y * t; - real_t zyxs = axis.z * sine; + real_t zyxs = axis.z * sin; Row0.y = xyzt - zyxs; Row1.x = xyzt + zyxs; xyzt = axis.x * axis.z * t; - zyxs = axis.y * sine; + zyxs = axis.y * sin; Row0.z = xyzt + zyxs; Row2.x = xyzt - zyxs; xyzt = axis.y * axis.z * t; - zyxs = axis.x * sine; + zyxs = axis.x * sin; Row1.z = xyzt - zyxs; Row2.y = xyzt + zyxs; } @@ -885,19 +885,29 @@ namespace Godot /// <param name="order">The order to compose the Euler angles.</param> public static Basis FromEuler(Vector3 euler, EulerOrder order = EulerOrder.Yxz) { - real_t c, s; - - c = Mathf.Cos(euler.x); - s = Mathf.Sin(euler.x); - Basis xmat = new Basis(new Vector3(1, 0, 0), new Vector3(0, c, s), new Vector3(0, -s, c)); + (real_t sin, real_t cos) = Mathf.SinCos(euler.x); + Basis xmat = new Basis + ( + new Vector3(1, 0, 0), + new Vector3(0, cos, sin), + new Vector3(0, -sin, cos) + ); - c = Mathf.Cos(euler.y); - s = Mathf.Sin(euler.y); - Basis ymat = new Basis(new Vector3(c, 0, -s), new Vector3(0, 1, 0), new Vector3(s, 0, c)); + (sin, cos) = Mathf.SinCos(euler.y); + Basis ymat = new Basis + ( + new Vector3(cos, 0, -sin), + new Vector3(0, 1, 0), + new Vector3(sin, 0, cos) + ); - c = Mathf.Cos(euler.z); - s = Mathf.Sin(euler.z); - Basis zmat = new Basis(new Vector3(c, s, 0), new Vector3(-s, c, 0), new Vector3(0, 0, 1)); + (sin, cos) = Mathf.SinCos(euler.z); + Basis zmat = new Basis + ( + new Vector3(cos, sin, 0), + new Vector3(-sin, cos, 0), + new Vector3(0, 0, 1) + ); switch (order) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs index ea05c1547c..72a1868964 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs @@ -83,6 +83,17 @@ namespace Godot } /// <summary> + /// Returns the sine and cosine of angle <paramref name="s"/> in radians. + /// </summary> + /// <param name="s">The angle in radians.</param> + /// <returns>The sine and cosine of that angle.</returns> + public static (real_t Sin, real_t Cos) SinCos(real_t s) + { + (double sin, double cos) = Math.SinCos(s); + return ((real_t)sin, (real_t)cos); + } + + /// <summary> /// Returns <see langword="true"/> if <paramref name="a"/> and <paramref name="b"/> are approximately /// equal to each other. /// The comparison is done using the provided tolerance value. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs index fd37f8d9e8..f11b3c553a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -381,14 +381,14 @@ namespace Godot } real_t radians = Mathf.DegToRad(fovyDegrees / (real_t)2.0); real_t deltaZ = zFar - zNear; - real_t sine = Mathf.Sin(radians); + (real_t sin, real_t cos) = Mathf.SinCos(radians); - if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) + if ((deltaZ == 0) || (sin == 0) || (aspect == 0)) { return Zero; } - real_t cotangent = Mathf.Cos(radians) / sine; + real_t cotangent = cos / sin; Projection proj = Projection.Identity; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index 47106bb402..8e4f9178f7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -542,14 +542,13 @@ namespace Godot } else { - real_t sinAngle = Mathf.Sin(angle * 0.5f); - real_t cosAngle = Mathf.Cos(angle * 0.5f); - real_t s = sinAngle / d; + (real_t sin, real_t cos) = Mathf.SinCos(angle * 0.5f); + real_t s = sin / d; x = axis.x * s; y = axis.y * s; z = axis.z * s; - w = cosAngle; + w = cos; } } @@ -593,12 +592,9 @@ namespace Godot // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6) // a3 is the angle of the first rotation, following the notation in this reference. - real_t cosA1 = Mathf.Cos(halfA1); - real_t sinA1 = Mathf.Sin(halfA1); - real_t cosA2 = Mathf.Cos(halfA2); - real_t sinA2 = Mathf.Sin(halfA2); - real_t cosA3 = Mathf.Cos(halfA3); - real_t sinA3 = Mathf.Sin(halfA3); + (real_t sinA1, real_t cosA1) = Mathf.SinCos(halfA1); + (real_t sinA2, real_t cosA2) = Mathf.SinCos(halfA2); + (real_t sinA3, real_t cosA3) = Mathf.SinCos(halfA3); return new Quaternion( (sinA1 * cosA2 * sinA3) + (cosA1 * sinA2 * cosA3), diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 6dda150c2b..fa060e3a53 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -195,8 +195,10 @@ namespace Godot Vector2 s2 = transform.GetScale(); // Slerp rotation - var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1)); - var v2 = new Vector2(Mathf.Cos(r2), Mathf.Sin(r2)); + (real_t sin1, real_t cos1) = Mathf.SinCos(r1); + (real_t sin2, real_t cos2) = Mathf.SinCos(r2); + var v1 = new Vector2(cos1, sin1); + var v2 = new Vector2(cos2, sin2); real_t dot = v1.Dot(v2); @@ -213,7 +215,8 @@ namespace Godot { real_t angle = weight * Mathf.Acos(dot); Vector2 v3 = (v2 - (v1 * dot)).Normalized(); - v = (v1 * Mathf.Cos(angle)) + (v3 * Mathf.Sin(angle)); + (real_t sine, real_t cos) = Mathf.SinCos(angle); + v = (v1 * sine) + (v3 * cos); } // Extract parameters @@ -434,8 +437,9 @@ namespace Godot /// <param name="origin">The origin vector, or column index 2.</param> public Transform2D(real_t rotation, Vector2 origin) { - x.x = y.y = Mathf.Cos(rotation); - x.y = y.x = Mathf.Sin(rotation); + (real_t sin, real_t cos) = Mathf.SinCos(rotation); + x.x = y.y = cos; + x.y = y.x = sin; y.x *= -1; this.origin = origin; } @@ -451,10 +455,12 @@ namespace Godot /// <param name="origin">The origin vector, or column index 2.</param> public Transform2D(real_t rotation, Vector2 scale, real_t skew, Vector2 origin) { - x.x = Mathf.Cos(rotation) * scale.x; - y.y = Mathf.Cos(rotation + skew) * scale.y; - y.x = -Mathf.Sin(rotation + skew) * scale.y; - x.y = Mathf.Sin(rotation) * scale.x; + (real_t rotationSin, real_t rotationCos) = Mathf.SinCos(rotation); + (real_t rotationSkewSin, real_t rotationSkewCos) = Mathf.SinCos(rotation + skew); + x.x = rotationCos * scale.x; + y.y = rotationSkewCos * scale.y; + y.x = -rotationSkewSin * scale.y; + x.y = rotationSin * scale.x; this.origin = origin; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 57cbef1c5c..1e88e18b3d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -539,11 +539,12 @@ namespace Godot /// <returns>The rotated vector.</returns> public readonly Vector2 Rotated(real_t angle) { - real_t sine = Mathf.Sin(angle); - real_t cosi = Mathf.Cos(angle); - return new Vector2( - x * cosi - y * sine, - x * sine + y * cosi); + (real_t sin, real_t cos) = Mathf.SinCos(angle); + return new Vector2 + ( + x * cos - y * sin, + x * sin + y * cos + ); } /// <summary> @@ -693,7 +694,8 @@ namespace Godot /// <returns>The resulting vector.</returns> public static Vector2 FromAngle(real_t angle) { - return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); + (real_t sin, real_t cos) = Mathf.SinCos(angle); + return new Vector2(cos, sin); } /// <summary> diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index ccd3480d11..87b599bc81 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -1572,7 +1572,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p int ret = unzGoToFirstFile(src_pkg_zip); Vector<uint8_t> project_file_data; while (ret == UNZ_OK) { -#if defined(MACOS_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED) bool is_execute = false; #endif @@ -1605,7 +1605,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p continue; //ignore! } found_library = true; -#if defined(MACOS_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED) is_execute = true; #endif file = file.replace(library_to_use, binary_name + ".xcframework"); @@ -1648,7 +1648,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->store_buffer(data.ptr(), data.size()); } -#if defined(MACOS_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED) if (is_execute) { // we need execute rights on this file chmod(file.utf8().get_data(), 0755); diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 747dcbd76c..f4d36f1a87 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -338,12 +338,17 @@ def configure(env: "Environment"): env.Prepend(CPPPATH=["#platform/linuxbsd"]) + env.Append( + CPPDEFINES=[ + "LINUXBSD_ENABLED", + "UNIX_ENABLED", + ("_FILE_OFFSET_BITS", 64), + ] + ) + if env["x11"]: env.Append(CPPDEFINES=["X11_ENABLED"]) - env.Append(CPPDEFINES=["UNIX_ENABLED"]) - env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) - if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 9c7e04c433..ef58386b45 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1402,7 +1402,7 @@ Control *Viewport::gui_find_control(const Point2 &p_global) { xform = sw->get_canvas_transform(); } - Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform); + Control *ret = _gui_find_control_at_pos(sw, p_global, xform); if (ret) { return ret; } @@ -1411,7 +1411,7 @@ Control *Viewport::gui_find_control(const Point2 &p_global) { return nullptr; } -Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) { +Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform) { if (!p_node->is_visible()) { return nullptr; // Canvas item hidden, discard. } @@ -1431,7 +1431,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ continue; } - Control *ret = _gui_find_control_at_pos(ci, p_global, matrix, r_inv_xform); + Control *ret = _gui_find_control_at_pos(ci, p_global, matrix); if (ret) { return ret; } @@ -1449,7 +1449,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ Control *drag_preview = _gui_get_drag_preview(); if (!drag_preview || (c != drag_preview && !drag_preview->is_ancestor_of(c))) { - r_inv_xform = matrix; return c; } @@ -1496,12 +1495,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Point2 mpos = mb->get_position(); if (mb->is_pressed()) { - Size2 pos = mpos; if (!gui.mouse_focus_mask.is_empty()) { // Do not steal mouse focus and stuff while a focus mask exists. gui.mouse_focus_mask.set_flag(mouse_button_to_mask(mb->get_button_index())); } else { - gui.mouse_focus = gui_find_control(pos); + gui.mouse_focus = gui_find_control(mpos); gui.last_mouse_focus = gui.mouse_focus; if (!gui.mouse_focus) { @@ -1520,10 +1518,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { mb = mb->xformed_by(Transform2D()); // Make a copy of the event. - mb->set_global_position(pos); - - pos = gui.focus_inv_xform.xform(pos); - + Point2 pos = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(mpos); mb->set_position(pos); #ifdef DEBUG_ENABLED @@ -1587,11 +1582,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { return; } - Size2 pos = mpos; - mb = mb->xformed_by(Transform2D()); // Make a copy. - mb->set_global_position(pos); - pos = gui.focus_inv_xform.xform(pos); + Point2 pos = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(mpos); mb->set_position(pos); Control *mouse_focus = gui.mouse_focus; @@ -1894,11 +1886,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { bool stopped = false; if (over->can_process()) { touch_event = touch_event->xformed_by(Transform2D()); // Make a copy. - if (over == gui.mouse_focus) { - pos = gui.focus_inv_xform.xform(pos); - } else { - pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); - } + pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); touch_event->set_position(pos); stopped = _gui_call_input(over, touch_event); } @@ -1913,11 +1901,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Control *over = control_id.is_valid() ? Object::cast_to<Control>(ObjectDB::get_instance(control_id)) : nullptr; if (over && over->can_process()) { touch_event = touch_event->xformed_by(Transform2D()); // Make a copy. - if (over == gui.last_mouse_focus) { - pos = gui.focus_inv_xform.xform(pos); - } else { - pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); - } + pos = gui.last_mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(pos); touch_event->set_position(pos); stopped = _gui_call_input(over, touch_event); @@ -1943,11 +1927,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { bool stopped = false; if (over->can_process()) { gesture_event = gesture_event->xformed_by(Transform2D()); // Make a copy. - if (over == gui.mouse_focus) { - pos = gui.focus_inv_xform.xform(pos); - } else { - pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); - } + pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos); gesture_event->set_position(pos); stopped = _gui_call_input(over, gesture_event); } @@ -2394,7 +2374,6 @@ void Viewport::_post_gui_grab_click_focus() { } gui.mouse_focus = focus_grabber; - gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse(); click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos); for (int i = 0; i < 3; i++) { diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 9f182682d7..603e92b071 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -374,7 +374,6 @@ private: ObjectID drag_preview_id; Ref<SceneTreeTimer> tooltip_timer; double tooltip_delay = 0.0; - Transform2D focus_inv_xform; bool roots_order_dirty = false; List<Control *> roots; int canvas_sort_index = 0; //for sorting items with canvas as root @@ -403,7 +402,7 @@ private: void _gui_call_notification(Control *p_control, int p_what); void _gui_sort_roots(); - Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform); + Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform); void _gui_input_event(Ref<InputEvent> p_event); void _perform_drop(Control *p_control = nullptr, Point2 p_pos = Point2()); diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 55f88d9bf1..df9dfaa276 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -769,6 +769,49 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, } } +static Vector2 compute_polyline_segment_dir(const Vector<Point2> &p_points, int p_index, const Vector2 &p_prev_segment_dir) { + int point_count = p_points.size(); + + bool is_last_point = (p_index == point_count - 1); + + Vector2 segment_dir; + + if (is_last_point) { + segment_dir = p_prev_segment_dir; + } else { + segment_dir = (p_points[p_index + 1] - p_points[p_index]).normalized(); + + if (segment_dir.is_zero_approx()) { + segment_dir = p_prev_segment_dir; + } + } + + return segment_dir; +} + +static Vector2 compute_polyline_edge_offset_clamped(const Vector2 &p_segment_dir, const Vector2 &p_prev_segment_dir) { + Vector2 bisector; + float length = 1.0f; + + bisector = (p_prev_segment_dir * p_segment_dir.length() - p_segment_dir * p_prev_segment_dir.length()).normalized(); + + float angle = atan2f(bisector.cross(p_prev_segment_dir), bisector.dot(p_prev_segment_dir)); + float sin_angle = sinf(angle); + + if (!Math::is_zero_approx(sin_angle) && !p_segment_dir.is_equal_approx(p_prev_segment_dir)) { + length = 1.0f / sin_angle; + length = CLAMP(length, -3.0f, 3.0f); + } else { + bisector = p_segment_dir.orthogonal(); + } + + if (bisector.is_zero_approx()) { + bisector = p_segment_dir.orthogonal(); + } + + return bisector * length; +} + void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { ERR_FAIL_COND(p_points.size() < 2); Item *canvas_item = canvas_item_owner.get_or_null(p_item); @@ -777,11 +820,30 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point Color color = Color(1, 1, 1, 1); Vector<int> indices; - int pc = p_points.size(); - int pc2 = pc * 2; + int point_count = p_points.size(); + int polyline_point_count = point_count * 2; + + bool loop = p_points[0].is_equal_approx(p_points[point_count - 1]); + Vector2 first_segment_dir; + Vector2 last_segment_dir; - Vector2 prev_t; - int j2; + // Search for first non-zero vector between two segments. + for (int i = 1; i < point_count; i++) { + first_segment_dir = (p_points[i] - p_points[i - 1]).normalized(); + + if (!first_segment_dir.is_zero_approx()) { + break; + } + } + + // Search for last non-zero vector between two segments. + for (int i = point_count - 1; i >= 1; i--) { + last_segment_dir = (p_points[i] - p_points[i - 1]).normalized(); + + if (!last_segment_dir.is_zero_approx()) { + break; + } + } Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>(); ERR_FAIL_COND(!pline); @@ -789,8 +851,8 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point PackedColorArray colors; PackedVector2Array points; - colors.resize(pc2); - points.resize(pc2); + colors.resize(polyline_point_count); + points.resize(polyline_point_count); Vector2 *points_ptr = points.ptrw(); Color *colors_ptr = colors.ptrw(); @@ -845,14 +907,14 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point PackedColorArray colors_left; PackedVector2Array points_left; - colors_left.resize(pc2); - points_left.resize(pc2); + colors_left.resize(polyline_point_count); + points_left.resize(polyline_point_count); PackedColorArray colors_right; PackedVector2Array points_right; - colors_right.resize(pc2); - points_right.resize(pc2); + colors_right.resize(polyline_point_count); + points_right.resize(polyline_point_count); Item::CommandPolygon *pline_begin = canvas_item->alloc_command<Item::CommandPolygon>(); ERR_FAIL_COND(!pline_begin); @@ -898,79 +960,81 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point Color *colors_left_ptr = colors_left.ptrw(); Color *colors_right_ptr = colors_right.ptrw(); - for (int i = 0, j = 0; i < pc; i++, j += 2) { - bool is_begin = i == 0; - bool is_end = i == pc - 1; + Vector2 prev_segment_dir; + for (int i = 0; i < point_count; i++) { + bool is_first_point = (i == 0); + bool is_last_point = (i == point_count - 1); - Vector2 t; - Vector2 end_border; - Vector2 begin_border; - if (is_end) { - t = prev_t; - end_border = (p_points[i] - p_points[i - 1]).normalized() * border_size; - } else { - t = (p_points[i + 1] - p_points[i]).normalized().orthogonal(); - if (is_begin) { - prev_t = t; - begin_border = (p_points[i] - p_points[i + 1]).normalized() * border_size; - } + Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir); + if (is_first_point && loop) { + prev_segment_dir = last_segment_dir; + } else if (is_last_point && loop) { + prev_segment_dir = first_segment_dir; } - j2 = j + 1; + Vector2 base_edge_offset; + if (is_first_point && !loop) { + base_edge_offset = first_segment_dir.orthogonal(); + } else if (is_last_point && !loop) { + base_edge_offset = last_segment_dir.orthogonal(); + } else { + base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir); + } - Vector2 dir = (t + prev_t).normalized(); - Vector2 tangent = dir * p_width * 0.5; - Vector2 border = dir * border_size; + Vector2 edge_offset = base_edge_offset * (p_width * 0.5f); + Vector2 border = base_edge_offset * border_size; Vector2 pos = p_points[i]; - points_ptr[j] = pos + tangent; - points_ptr[j2] = pos - tangent; + points_ptr[i * 2 + 0] = pos + edge_offset; + points_ptr[i * 2 + 1] = pos - edge_offset; - points_left_ptr[j] = pos + tangent + border; - points_left_ptr[j2] = pos + tangent; + points_left_ptr[i * 2 + 0] = pos + edge_offset + border; + points_left_ptr[i * 2 + 1] = pos + edge_offset; - points_right_ptr[j] = pos - tangent; - points_right_ptr[j2] = pos - tangent - border; + points_right_ptr[i * 2 + 0] = pos - edge_offset; + points_right_ptr[i * 2 + 1] = pos - edge_offset - border; if (i < p_colors.size()) { color = p_colors[i]; color2 = Color(color.r, color.g, color.b, 0); } - colors_ptr[j] = color; - colors_ptr[j2] = color; + colors_ptr[i * 2 + 0] = color; + colors_ptr[i * 2 + 1] = color; - colors_left_ptr[j] = color2; - colors_left_ptr[j2] = color; + colors_left_ptr[i * 2 + 0] = color2; + colors_left_ptr[i * 2 + 1] = color; - colors_right_ptr[j] = color; - colors_right_ptr[j2] = color2; + colors_right_ptr[i * 2 + 0] = color; + colors_right_ptr[i * 2 + 1] = color2; - if (is_begin) { - points_begin_ptr[0] = pos + tangent + begin_border; - points_begin_ptr[1] = pos - tangent + begin_border; - points_begin_ptr[2] = pos + tangent; - points_begin_ptr[3] = pos - tangent; + if (is_first_point) { + Vector2 begin_border = loop ? Vector2() : -segment_dir * border_size; + + points_begin_ptr[0] = pos + edge_offset + begin_border; + points_begin_ptr[1] = pos - edge_offset + begin_border; + points_begin_ptr[2] = pos + edge_offset; + points_begin_ptr[3] = pos - edge_offset; colors_begin_ptr[0] = color2; colors_begin_ptr[1] = color2; colors_begin_ptr[2] = color; colors_begin_ptr[3] = color; - points_begin_left_corner_ptr[0] = pos - tangent - border; - points_begin_left_corner_ptr[1] = pos - tangent + begin_border - border; - points_begin_left_corner_ptr[2] = pos - tangent; - points_begin_left_corner_ptr[3] = pos - tangent + begin_border; + points_begin_left_corner_ptr[0] = pos - edge_offset - border; + points_begin_left_corner_ptr[1] = pos - edge_offset + begin_border - border; + points_begin_left_corner_ptr[2] = pos - edge_offset; + points_begin_left_corner_ptr[3] = pos - edge_offset + begin_border; colors_begin_left_corner_ptr[0] = color2; colors_begin_left_corner_ptr[1] = color2; colors_begin_left_corner_ptr[2] = color; colors_begin_left_corner_ptr[3] = color2; - points_begin_right_corner_ptr[0] = pos + tangent + begin_border; - points_begin_right_corner_ptr[1] = pos + tangent + begin_border + border; - points_begin_right_corner_ptr[2] = pos + tangent; - points_begin_right_corner_ptr[3] = pos + tangent + border; + points_begin_right_corner_ptr[0] = pos + edge_offset + begin_border; + points_begin_right_corner_ptr[1] = pos + edge_offset + begin_border + border; + points_begin_right_corner_ptr[2] = pos + edge_offset; + points_begin_right_corner_ptr[3] = pos + edge_offset + border; colors_begin_right_corner_ptr[0] = color2; colors_begin_right_corner_ptr[1] = color2; @@ -978,31 +1042,33 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point colors_begin_right_corner_ptr[3] = color2; } - if (is_end) { - points_end_ptr[0] = pos + tangent + end_border; - points_end_ptr[1] = pos - tangent + end_border; - points_end_ptr[2] = pos + tangent; - points_end_ptr[3] = pos - tangent; + if (is_last_point) { + Vector2 end_border = loop ? Vector2() : prev_segment_dir * border_size; + + points_end_ptr[0] = pos + edge_offset + end_border; + points_end_ptr[1] = pos - edge_offset + end_border; + points_end_ptr[2] = pos + edge_offset; + points_end_ptr[3] = pos - edge_offset; colors_end_ptr[0] = color2; colors_end_ptr[1] = color2; colors_end_ptr[2] = color; colors_end_ptr[3] = color; - points_end_left_corner_ptr[0] = pos - tangent - border; - points_end_left_corner_ptr[1] = pos - tangent + end_border - border; - points_end_left_corner_ptr[2] = pos - tangent; - points_end_left_corner_ptr[3] = pos - tangent + end_border; + points_end_left_corner_ptr[0] = pos - edge_offset - border; + points_end_left_corner_ptr[1] = pos - edge_offset + end_border - border; + points_end_left_corner_ptr[2] = pos - edge_offset; + points_end_left_corner_ptr[3] = pos - edge_offset + end_border; colors_end_left_corner_ptr[0] = color2; colors_end_left_corner_ptr[1] = color2; colors_end_left_corner_ptr[2] = color; colors_end_left_corner_ptr[3] = color2; - points_end_right_corner_ptr[0] = pos + tangent + end_border; - points_end_right_corner_ptr[1] = pos + tangent + end_border + border; - points_end_right_corner_ptr[2] = pos + tangent; - points_end_right_corner_ptr[3] = pos + tangent + border; + points_end_right_corner_ptr[0] = pos + edge_offset + end_border; + points_end_right_corner_ptr[1] = pos + edge_offset + end_border + border; + points_end_right_corner_ptr[2] = pos + edge_offset; + points_end_right_corner_ptr[3] = pos + edge_offset + border; colors_end_right_corner_ptr[0] = color2; colors_end_right_corner_ptr[1] = color2; @@ -1010,7 +1076,7 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point colors_end_right_corner_ptr[3] = color2; } - prev_t = t; + prev_segment_dir = segment_dir; } pline_begin->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; @@ -1039,33 +1105,41 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point } else { // Makes a single triangle strip for drawing the line. - for (int i = 0, j = 0; i < pc; i++, j += 2) { - Vector2 t; - if (i == pc - 1) { - t = prev_t; - } else { - t = (p_points[i + 1] - p_points[i]).normalized().orthogonal(); - if (i == 0) { - prev_t = t; - } + Vector2 prev_segment_dir; + for (int i = 0; i < point_count; i++) { + bool is_first_point = (i == 0); + bool is_last_point = (i == point_count - 1); + + Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir); + if (is_first_point && loop) { + prev_segment_dir = last_segment_dir; + } else if (is_last_point && loop) { + prev_segment_dir = first_segment_dir; } - j2 = j + 1; + Vector2 base_edge_offset; + if (is_first_point && !loop) { + base_edge_offset = first_segment_dir.orthogonal(); + } else if (is_last_point && !loop) { + base_edge_offset = last_segment_dir.orthogonal(); + } else { + base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir); + } - Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; + Vector2 edge_offset = base_edge_offset * (p_width * 0.5f); Vector2 pos = p_points[i]; - points_ptr[j] = pos + tangent; - points_ptr[j2] = pos - tangent; + points_ptr[i * 2 + 0] = pos + edge_offset; + points_ptr[i * 2 + 1] = pos - edge_offset; if (i < p_colors.size()) { color = p_colors[i]; } - colors_ptr[j] = color; - colors_ptr[j2] = color; + colors_ptr[i * 2 + 0] = color; + colors_ptr[i * 2 + 1] = color; - prev_t = t; + prev_segment_dir = segment_dir; } } |