summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/input/input_builders.py2
-rw-r--r--drivers/unix/dir_access_unix.cpp4
-rw-r--r--editor/import/resource_importer_obj.cpp13
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp4
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_editor.cpp8
-rw-r--r--modules/gdscript/gdscript_parser.cpp54
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class_name.gd2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs50
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs24
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs14
-rw-r--r--platform/ios/export/export_plugin.cpp6
-rw-r--r--platform/linuxbsd/detect.py11
-rw-r--r--scene/main/viewport.cpp39
-rw-r--r--scene/main/viewport.h3
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp242
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;
}
}