From db9921b17f8c6971628e4e2687e043a1e87198a5 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Wed, 8 Oct 2025 14:55:42 +0100 Subject: [PATCH 1/3] Add `Span` and some basic uses from `Geometry`. --- core/cowdata.h | 4 + core/local_vector.h | 13 ++ core/math/bvh.h | 2 +- core/math/delaunay.h | 17 ++- core/math/geometry.cpp | 8 +- core/math/geometry.h | 4 +- core/math/octree_definition.inc | 2 +- core/span.h | 220 +++++++++++++++++++++++++++++++ core/vector.h | 4 + editor/spatial_editor_gizmos.cpp | 2 +- scene/3d/room.cpp | 2 +- scene/3d/room_manager.cpp | 4 +- 12 files changed, 264 insertions(+), 18 deletions(-) create mode 100644 core/span.h diff --git a/core/cowdata.h b/core/cowdata.h index ef913b6e6ac..0fc0f01fd43 100644 --- a/core/cowdata.h +++ b/core/cowdata.h @@ -38,6 +38,7 @@ #include "core/error_macros.h" #include "core/os/memory.h" #include "core/safe_refcount.h" +#include "core/span.h" template class Vector; @@ -132,6 +133,9 @@ public: } } + _FORCE_INLINE_ operator Span() const { return Span(ptr(), size()); } + _FORCE_INLINE_ Span span() const { return operator Span(); } + _FORCE_INLINE_ void clear() { resize(0); } _FORCE_INLINE_ bool empty() const { return _ptr == nullptr; } diff --git a/core/local_vector.h b/core/local_vector.h index 5c64f76dc4e..9c45ee9fe18 100644 --- a/core/local_vector.h +++ b/core/local_vector.h @@ -35,6 +35,7 @@ #include "core/os/memory.h" #include "core/pool_vector.h" #include "core/sort_array.h" +#include "core/span.h" #include "core/vector.h" #include @@ -283,6 +284,9 @@ public: return ret; } + _FORCE_INLINE_ Span span() const { return Span(data, count); } + _FORCE_INLINE_ operator Span() const { return span(); } + _FORCE_INLINE_ LocalVector() {} _FORCE_INLINE_ LocalVector(const LocalVector &p_from) { resize(p_from.size()); @@ -290,12 +294,21 @@ public: data[i] = p_from.data[i]; } } + + LocalVector(const Span &p_from) { + resize(p_from.size()); + for (U i = 0; i < count; i++) { + data[i] = p_from[i]; + } + } + LocalVector(const Vector &p_from) { resize(p_from.size()); for (U i = 0; i < count; i++) { data[i] = p_from[i]; } } + LocalVector(const PoolVector &p_from) { resize(p_from.size()); typename PoolVector::Read r = p_from.read(); diff --git a/core/math/bvh.h b/core/math/bvh.h index 57362a908dc..a56573fc901 100644 --- a/core/math/bvh.h +++ b/core/math/bvh.h @@ -396,7 +396,7 @@ public: return 0; } - Vector convex_points = Geometry::compute_convex_mesh_points(&p_convex[0], p_convex.size()); + Vector convex_points = Geometry::compute_convex_mesh_points(p_convex); if (convex_points.size() == 0) { return 0; } diff --git a/core/math/delaunay.h b/core/math/delaunay.h index 5a6f76a3125..751db4e2bb7 100644 --- a/core/math/delaunay.h +++ b/core/math/delaunay.h @@ -31,6 +31,7 @@ #ifndef DELAUNAY_H #define DELAUNAY_H +#include "core/local_vector.h" #include "core/math/rect2.h" class Delaunay2D { @@ -58,7 +59,7 @@ public: } }; - static bool circum_circle_contains(const Vector &p_vertices, const Triangle &p_triangle, int p_vertex) { + static bool circum_circle_contains(const Span &p_vertices, const Triangle &p_triangle, int p_vertex) { Vector2 p1 = p_vertices[p_triangle.points[0]]; Vector2 p2 = p_vertices[p_triangle.points[1]]; Vector2 p3 = p_vertices[p_triangle.points[2]]; @@ -77,7 +78,7 @@ public: return d <= r; } - static bool edge_compare(const Vector &p_vertices, const Edge &p_a, const Edge &p_b) { + static bool edge_compare(const Span &p_vertices, const Edge &p_a, const Edge &p_b) { if (p_vertices[p_a.edge[0]].is_equal_approx(p_vertices[p_b.edge[0]]) && p_vertices[p_a.edge[1]].is_equal_approx(p_vertices[p_b.edge[1]])) { return true; } @@ -89,12 +90,12 @@ public: return false; } - static Vector triangulate(const Vector &p_points) { - Vector points = p_points; + static Vector triangulate(const Span &p_points) { + LocalVector points(p_points); Vector triangles; Rect2 rect; - for (int i = 0; i < p_points.size(); i++) { + for (uint32_t i = 0; i < p_points.size(); i++) { if (i == 0) { rect.position = p_points[i]; } else { @@ -111,7 +112,7 @@ public: triangles.push_back(Triangle(p_points.size() + 0, p_points.size() + 1, p_points.size() + 2)); - for (int i = 0; i < p_points.size(); i++) { + for (uint32_t i = 0; i < p_points.size(); i++) { //std::cout << "Traitement du point " << *p << std::endl; //std::cout << "_triangles contains " << _triangles.size() << " elements" << std::endl; @@ -150,10 +151,12 @@ public: } } + int point_count = p_points.size(); + for (int i = 0; i < triangles.size(); i++) { bool invalid = false; for (int j = 0; j < 3; j++) { - if (triangles[i].points[j] >= p_points.size()) { + if (triangles[i].points[j] >= point_count) { invalid = true; break; } diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index b86d44c4e28..6784e317f3f 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -1398,11 +1398,13 @@ bool Geometry::convex_hull_intersects_convex_hull(const Plane *p_planes_a, int p return false; } -Vector Geometry::compute_convex_mesh_points(const Plane *p_planes, int p_plane_count, real_t p_epsilon) { +Vector Geometry::compute_convex_mesh_points(const Span &p_planes, real_t p_epsilon) { Vector points; // Iterate through every unique combination of any three planes. - for (int i = p_plane_count - 1; i >= 0; i--) { + int plane_count = p_planes.size(); + + for (int i = plane_count - 1; i >= 0; i--) { for (int j = i - 1; j >= 0; j--) { for (int k = j - 1; k >= 0; k--) { // Find the point where these planes all cross over (if they @@ -1412,7 +1414,7 @@ Vector Geometry::compute_convex_mesh_points(const Plane *p_planes, int // See if any *other* plane excludes this point because it's // on the wrong side. bool excluded = false; - for (int n = 0; n < p_plane_count; n++) { + for (int n = 0; n < plane_count; n++) { if (n != i && n != j && n != k) { real_t dist = p_planes[n].distance_to(convex_shape_point); if (dist > p_epsilon) { diff --git a/core/math/geometry.h b/core/math/geometry.h index c530e93f55c..4ef9624dac6 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -806,7 +806,7 @@ public: return _polypath_offset(p_polygon, p_delta, p_join_type, p_end_type); } - static Vector triangulate_delaunay_2d(const Vector &p_points) { + static Vector triangulate_delaunay_2d(const Span &p_points) { Vector tr = Delaunay2D::triangulate(p_points); Vector triangles; @@ -1017,7 +1017,7 @@ public: }; static Vector partial_pack_rects(const Vector &p_sizes, const Size2i &p_atlas_size); - static Vector compute_convex_mesh_points(const Plane *p_planes, int p_plane_count, real_t p_epsilon = CMP_EPSILON); + static Vector compute_convex_mesh_points(const Span &p_planes, real_t p_epsilon = CMP_EPSILON); static bool convex_hull_intersects_convex_hull(const Plane *p_planes_a, int p_plane_count_a, const Plane *p_planes_b, int p_plane_count_b); static real_t calculate_convex_hull_volume(const Geometry::MeshData &p_md); static bool verify_indices(const int *p_indices, int p_num_indices, int p_num_vertices); diff --git a/core/math/octree_definition.inc b/core/math/octree_definition.inc index 39f5bfe66a3..6e8d808b9b5 100644 --- a/core/math/octree_definition.inc +++ b/core/math/octree_definition.inc @@ -1575,7 +1575,7 @@ OCTREE_FUNC(int)::cull_convex(const Vector &p_convex, T **p_result_array, return 0; } - Vector convex_points = Geometry::compute_convex_mesh_points(&p_convex[0], p_convex.size()); + Vector convex_points = Geometry::compute_convex_mesh_points(p_convex); if (convex_points.size() == 0) { return 0; } diff --git a/core/span.h b/core/span.h new file mode 100644 index 00000000000..bb899c796c7 --- /dev/null +++ b/core/span.h @@ -0,0 +1,220 @@ +/**************************************************************************/ +/* span.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#pragma once + +#include "core/error_macros.h" +#include "core/typedefs.h" + +// Equivalent of std::span. +// Represents a view into a contiguous memory space. +// DISCLAIMER: This data type does not own the underlying buffer. DO NOT STORE IT. +// Additionally, for the lifetime of the Span, do not resize the buffer, and do not insert or remove elements from it. +// Failure to respect this may lead to crashes or undefined behavior. +template +class Span { + const T *_ptr = nullptr; + U _len = 0; + +public: + static constexpr bool is_string = std::disjunction_v< + std::is_same, + std::is_same, + std::is_same, + std::is_same>; + + _FORCE_INLINE_ constexpr Span() = default; + + _FORCE_INLINE_ Span(const T *p_ptr, U p_len) : + _ptr(p_ptr), _len(p_len) { +#ifdef DEBUG_ENABLED + // TODO In c++20, make this check run only in non-consteval, and make this constructor constexpr. + if (_ptr == nullptr && _len > 0) { + ERR_PRINT("Internal bug, please report: Span was created from nullptr with size > 0. Recovering by using size = 0."); + _len = 0; + } +#endif + } + + // Allows creating Span directly from C arrays and string literals. + template + _FORCE_INLINE_ constexpr Span(const T (&p_array)[N]) : + _ptr(p_array), _len(N) { + if constexpr (is_string) { + // Cut off the \0 terminator implicitly added to string literals. + if (N > 0 && p_array[N - 1] == '\0') { + _len--; + } + } + } + + _FORCE_INLINE_ constexpr U size() const { return _len; } + _FORCE_INLINE_ constexpr bool is_empty() const { return _len == 0; } + + _FORCE_INLINE_ constexpr const T *ptr() const { return _ptr; } + + // NOTE: Span subscripts sanity check the bounds to avoid undefined behavior. + // This is slower than direct buffer access and can prevent autovectorization. + // If the bounds are known, use ptr() subscript instead. + _FORCE_INLINE_ constexpr const T &operator[](U p_idx) const { + CRASH_COND(p_idx >= _len); + return _ptr[p_idx]; + } + + _FORCE_INLINE_ constexpr const T *begin() const { return _ptr; } + _FORCE_INLINE_ constexpr const T *end() const { return _ptr + _len; } + + template + _FORCE_INLINE_ constexpr Span reinterpret() const { + return Span(reinterpret_cast(_ptr), _len * sizeof(T) / sizeof(T1)); + } + + // Algorithms. + constexpr int64_t find(const T &p_val, U p_from = 0) const; + constexpr int64_t find_sequence(const Span &p_span, U p_from = 0) const; + constexpr int64_t rfind(const T &p_val, U p_from) const; + _FORCE_INLINE_ constexpr int64_t rfind(const T &p_val) const { return rfind(p_val, size() - 1); } + constexpr int64_t rfind_sequence(const Span &p_span, U p_from) const; + _FORCE_INLINE_ constexpr int64_t rfind_sequence(const Span &p_span) const { return rfind_sequence(p_span, size() - p_span.size()); } + constexpr U count(const T &p_val) const; + /// Find the index of the given value using binary search. + /// Note: Assumes that elements in the span are sorted. Otherwise, use find() instead. + template > + constexpr U bisect(const T &p_value, bool p_before, Comparator compare = Comparator()) const; + + /// The caller is responsible to ensure size() > 0. + constexpr T max() const; +}; + +template +constexpr int64_t Span::find(const T &p_val, U p_from) const { + for (U i = p_from; i < size(); i++) { + if (ptr()[i] == p_val) { + return i; + } + } + return -1; +} + +template +constexpr int64_t Span::find_sequence(const Span &p_span, U p_from) const { + for (U i = p_from; i <= size() - p_span.size(); i++) { + bool found = true; + for (U j = 0; j < p_span.size(); j++) { + if (ptr()[i + j] != p_span.ptr()[j]) { + found = false; + break; + } + } + if (found) { + return i; + } + } + + return -1; +} + +template +constexpr int64_t Span::rfind(const T &p_val, U p_from) const { + for (int64_t i = p_from; i >= 0; i--) { + if (ptr()[i] == p_val) { + return i; + } + } + return -1; +} + +template +constexpr int64_t Span::rfind_sequence(const Span &p_span, U p_from) const { + for (int64_t i = p_from; i >= 0; i--) { + bool found = true; + for (U j = 0; j < p_span.size(); j++) { + if (ptr()[i + j] != p_span.ptr()[j]) { + found = false; + break; + } + } + if (found) { + return i; + } + } + + return -1; +} + +template +constexpr U Span::count(const T &p_val) const { + U amount = 0; + for (U i = 0; i < size(); i++) { + if (ptr()[i] == p_val) { + amount++; + } + } + return amount; +} + +template +template +constexpr U Span::bisect(const T &p_value, bool p_before, Comparator compare) const { + U lo = 0; + U hi = size(); + if (p_before) { + while (lo < hi) { + const U mid = (lo + hi) / 2; + if (compare(ptr()[mid], p_value)) { + lo = mid + 1; + } else { + hi = mid; + } + } + } else { + while (lo < hi) { + const U mid = (lo + hi) / 2; + if (compare(p_value, ptr()[mid])) { + hi = mid; + } else { + lo = mid + 1; + } + } + } + return lo; +} + +template +constexpr T Span::max() const { + DEV_ASSERT(size() > 0); + T max_val = _ptr[0]; + for (U i = 1; i < _len; ++i) { + if (_ptr[i] > max_val) { + max_val = _ptr[i]; + } + } + return max_val; +} diff --git a/core/vector.h b/core/vector.h index d1b89011e6d..32fcaf4c605 100644 --- a/core/vector.h +++ b/core/vector.h @@ -84,6 +84,10 @@ public: _FORCE_INLINE_ const T &get(int p_index) const { return _cowdata.get(p_index); } _FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } _FORCE_INLINE_ int size() const { return _cowdata.size(); } + + _FORCE_INLINE_ operator Span() const { return _cowdata.span(); } + _FORCE_INLINE_ Span span() const { return _cowdata.span(); } + Error resize(int p_size) { return _cowdata.resize(p_size); } _FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); } Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); } diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index a4b7f25d435..e4ab695b3d4 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -535,7 +535,7 @@ bool EditorSpatialGizmo::intersect_frustum(const Camera *p_camera, const Vector< transformed_frustum.push_back(it.xform(p_frustum[i])); } - Vector convex_points = Geometry::compute_convex_mesh_points(p_frustum.ptr(), p_frustum.size()); + Vector convex_points = Geometry::compute_convex_mesh_points(p_frustum); if (collision_mesh->inside_convex_shape(transformed_frustum.ptr(), transformed_frustum.size(), convex_points.ptr(), convex_points.size(), mesh_scale)) { return true; diff --git a/scene/3d/room.cpp b/scene/3d/room.cpp index 0c0894acc67..088b03acbd8 100644 --- a/scene/3d/room.cpp +++ b/scene/3d/room.cpp @@ -172,7 +172,7 @@ PoolVector Room::generate_points() { scaled_epsilon = MAX(scaled_epsilon * 0.01, 0.001); LocalVector pts; - pts = Geometry::compute_convex_mesh_points(&_planes[0], _planes.size(), scaled_epsilon); + pts = Geometry::compute_convex_mesh_points(Span(_planes.ptr(), _planes.size()), scaled_epsilon); // eliminate duplicates for (int n = 0; n < pts.size(); n++) { diff --git a/scene/3d/room_manager.cpp b/scene/3d/room_manager.cpp index a55e36fdbb8..86cc69b5b02 100644 --- a/scene/3d/room_manager.cpp +++ b/scene/3d/room_manager.cpp @@ -784,7 +784,7 @@ void RoomManager::_generate_room_overlap_zones() { memcpy(dest, &other->_planes[0], other->_planes.size() * sizeof(Plane)); - Vector overlap_pts = Geometry::compute_convex_mesh_points(planes.ptr(), planes.size()); + Vector overlap_pts = Geometry::compute_convex_mesh_points(Span(planes.ptr(), planes.size())); if (overlap_pts.size() < 4) { continue; @@ -1642,7 +1642,7 @@ void RoomManager::_build_simplified_bound(const Room *p_room, Geometry::MeshData return; } - Vector pts = Geometry::compute_convex_mesh_points(&r_planes[0], r_planes.size(), 0.001); + Vector pts = Geometry::compute_convex_mesh_points(Span(r_planes.ptr(), r_planes.size()), 0.001); Error err = _build_room_convex_hull(p_room, pts, r_md); if (err != OK) { From c59ef6918497583a7f57044998d735203c496563 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Thu, 9 Oct 2025 05:28:01 +0100 Subject: [PATCH 2/3] `Span` - update more `Geometry` API to use span --- core/math/geometry.cpp | 24 ++++++++++++------------ core/math/geometry.h | 30 +++++++++++++++--------------- core/math/triangulate.cpp | 6 +++--- core/math/triangulate.h | 6 +++--- core/pool_vector.h | 3 +++ scene/2d/collision_polygon_2d.cpp | 2 +- scene/2d/light_occluder_2d.cpp | 2 +- scene/2d/navigation_polygon.cpp | 2 +- 8 files changed, 39 insertions(+), 36 deletions(-) diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index 6784e317f3f..d937c81f406 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -1042,7 +1042,7 @@ struct _AtlasWorkRectResult { int max_h; }; -void Geometry::make_atlas(const Vector &p_rects, Vector &r_result, Size2i &r_size) { +void Geometry::make_atlas(const Span &p_rects, Vector &r_result, Size2i &r_size) { // Super simple, almost brute force scanline stacking fitter. // It's pretty basic for now, but it tries to make sure that the aspect ratio of the // resulting atlas is somehow square. This is necessary because video cards have limits. @@ -1052,14 +1052,14 @@ void Geometry::make_atlas(const Vector &p_rects, Vector &r_resu // 256x8192 atlas (won't work anywhere). ERR_FAIL_COND(p_rects.size() == 0); - for (int i = 0; i < p_rects.size(); i++) { + for (uint32_t i = 0; i < p_rects.size(); i++) { ERR_FAIL_COND(p_rects[i].width <= 0); ERR_FAIL_COND(p_rects[i].height <= 0); } Vector<_AtlasWorkRect> wrects; wrects.resize(p_rects.size()); - for (int i = 0; i < p_rects.size(); i++) { + for (uint32_t i = 0; i < p_rects.size(); i++) { wrects.write[i].s = p_rects[i]; wrects.write[i].idx = i; } @@ -1146,14 +1146,14 @@ void Geometry::make_atlas(const Vector &p_rects, Vector &r_resu r_result.resize(p_rects.size()); - for (int i = 0; i < p_rects.size(); i++) { + for (uint32_t i = 0; i < p_rects.size(); i++) { r_result.write[results[best].result[i].idx] = results[best].result[i].p; } r_size = Size2(results[best].max_w, results[best].max_h); } -Vector> Geometry::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector &p_polypath_a, const Vector &p_polypath_b, bool is_a_open) { +Vector> Geometry::_polypaths_do_operation(PolyBooleanOperation p_op, const Span &p_polypath_a, const Span &p_polypath_b, bool is_a_open) { using namespace ClipperLib; ClipType op = ctUnion; @@ -1175,10 +1175,10 @@ Vector> Geometry::_polypaths_do_operation(PolyBooleanOperation p_ Path path_a, path_b; // Need to scale points (Clipper's requirement for robust computation). - for (int i = 0; i != p_polypath_a.size(); ++i) { + for (uint32_t i = 0; i != p_polypath_a.size(); ++i) { path_a << IntPoint(p_polypath_a[i].x * (real_t)SCALE_FACTOR, p_polypath_a[i].y * (real_t)SCALE_FACTOR); } - for (int i = 0; i != p_polypath_b.size(); ++i) { + for (uint32_t i = 0; i != p_polypath_b.size(); ++i) { path_b << IntPoint(p_polypath_b[i].x * (real_t)SCALE_FACTOR, p_polypath_b[i].y * (real_t)SCALE_FACTOR); } Clipper clp; @@ -1212,7 +1212,7 @@ Vector> Geometry::_polypaths_do_operation(PolyBooleanOperation p_ return polypaths; } -Vector> Geometry::_polypath_offset(const Vector &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { +Vector> Geometry::_polypath_offset(const Span &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { using namespace ClipperLib; JoinType jt = jtSquare; @@ -1252,7 +1252,7 @@ Vector> Geometry::_polypath_offset(const Vector &p_polypa Path path; // Need to scale points (Clipper's requirement for robust computation). - for (int i = 0; i != p_polypath.size(); ++i) { + for (uint32_t i = 0; i != p_polypath.size(); ++i) { path << IntPoint(p_polypath[i].x * (real_t)SCALE_FACTOR, p_polypath[i].y * (real_t)SCALE_FACTOR); } co.AddPath(path, jt, et); @@ -1436,7 +1436,7 @@ Vector Geometry::compute_convex_mesh_points(const Span &p_planes return points; } -Vector Geometry::partial_pack_rects(const Vector &p_sizes, const Size2i &p_atlas_size) { +Vector Geometry::partial_pack_rects(const Span &p_sizes, const Size2i &p_atlas_size) { Vector nodes; nodes.resize(p_atlas_size.width); memset(nodes.ptrw(), 0, sizeof(stbrp_node) * nodes.size()); @@ -1447,7 +1447,7 @@ Vector Geometry::partial_pack_rects(const Vector rects; rects.resize(p_sizes.size()); - for (int i = 0; i < p_sizes.size(); i++) { + for (uint32_t i = 0; i < p_sizes.size(); i++) { rects.write[i].id = i; rects.write[i].w = p_sizes[i].width; rects.write[i].h = p_sizes[i].height; @@ -1461,7 +1461,7 @@ Vector Geometry::partial_pack_rects(const Vector ret; ret.resize(p_sizes.size()); - for (int i = 0; i < p_sizes.size(); i++) { + for (uint32_t i = 0; i < p_sizes.size(); i++) { ret.write[rects[i].id] = { rects[i].x, rects[i].y, static_cast(rects[i].was_packed) }; } diff --git a/core/math/geometry.h b/core/math/geometry.h index 4ef9624dac6..56fb29e5e68 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -772,35 +772,35 @@ public: END_ROUND }; - static Vector> merge_polygons_2d(const Vector &p_polygon_a, const Vector &p_polygon_b) { + static Vector> merge_polygons_2d(const Span &p_polygon_a, const Span &p_polygon_b) { return _polypaths_do_operation(OPERATION_UNION, p_polygon_a, p_polygon_b); } - static Vector> clip_polygons_2d(const Vector &p_polygon_a, const Vector &p_polygon_b) { + static Vector> clip_polygons_2d(const Span &p_polygon_a, const Span &p_polygon_b) { return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polygon_a, p_polygon_b); } - static Vector> intersect_polygons_2d(const Vector &p_polygon_a, const Vector &p_polygon_b) { + static Vector> intersect_polygons_2d(const Span &p_polygon_a, const Span &p_polygon_b) { return _polypaths_do_operation(OPERATION_INTERSECTION, p_polygon_a, p_polygon_b); } - static Vector> exclude_polygons_2d(const Vector &p_polygon_a, const Vector &p_polygon_b) { + static Vector> exclude_polygons_2d(const Span &p_polygon_a, const Span &p_polygon_b) { return _polypaths_do_operation(OPERATION_XOR, p_polygon_a, p_polygon_b); } - static Vector> clip_polyline_with_polygon_2d(const Vector &p_polyline, const Vector &p_polygon) { + static Vector> clip_polyline_with_polygon_2d(const Span &p_polyline, const Span &p_polygon) { return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polyline, p_polygon, true); } - static Vector> intersect_polyline_with_polygon_2d(const Vector &p_polyline, const Vector &p_polygon) { + static Vector> intersect_polyline_with_polygon_2d(const Span &p_polyline, const Span &p_polygon) { return _polypaths_do_operation(OPERATION_INTERSECTION, p_polyline, p_polygon, true); } - static Vector> offset_polygon_2d(const Vector &p_polygon, real_t p_delta, PolyJoinType p_join_type) { + static Vector> offset_polygon_2d(const Span &p_polygon, real_t p_delta, PolyJoinType p_join_type) { return _polypath_offset(p_polygon, p_delta, p_join_type, END_POLYGON); } - static Vector> offset_polyline_2d(const Vector &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { + static Vector> offset_polyline_2d(const Span &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { ERR_FAIL_COND_V_MSG(p_end_type == END_POLYGON, Vector>(), "Attempt to offset a polyline like a polygon (use offset_polygon_2d instead)."); return _polypath_offset(p_polygon, p_delta, p_join_type, p_end_type); @@ -818,7 +818,7 @@ public: return triangles; } - static Vector triangulate_polygon(const Vector &p_polygon) { + static Vector triangulate_polygon(const Span &p_polygon) { Vector triangles; if (!Triangulate::triangulate(p_polygon, triangles)) { return Vector(); //fail @@ -826,7 +826,7 @@ public: return triangles; } - static bool is_polygon_clockwise(const Vector &p_polygon) { + static bool is_polygon_clockwise(const Span &p_polygon) { int c = p_polygon.size(); if (c < 3) { return false; @@ -843,7 +843,7 @@ public: } // Alternate implementation that should be faster. - static bool is_point_in_polygon(const Vector2 &p_point, const Vector &p_polygon) { + static bool is_point_in_polygon(const Vector2 &p_point, const Span &p_polygon) { int c = p_polygon.size(); if (c < 3) { return false; @@ -1008,14 +1008,14 @@ public: static void sort_polygon_winding(Vector &r_verts, bool p_clockwise = true); static real_t find_polygon_area(const Vector3 *p_verts, int p_num_verts); - static void make_atlas(const Vector &p_rects, Vector &r_result, Size2i &r_size); + static void make_atlas(const Span &p_rects, Vector &r_result, Size2i &r_size); struct PackRectsResult { int x; int y; bool packed; }; - static Vector partial_pack_rects(const Vector &p_sizes, const Size2i &p_atlas_size); + static Vector partial_pack_rects(const Span &p_sizes, const Size2i &p_atlas_size); static Vector compute_convex_mesh_points(const Span &p_planes, real_t p_epsilon = CMP_EPSILON); static bool convex_hull_intersects_convex_hull(const Plane *p_planes_a, int p_plane_count_a, const Plane *p_planes_b, int p_plane_count_b); @@ -1023,8 +1023,8 @@ public: static bool verify_indices(const int *p_indices, int p_num_indices, int p_num_vertices); private: - static Vector> _polypaths_do_operation(PolyBooleanOperation p_op, const Vector &p_polypath_a, const Vector &p_polypath_b, bool is_a_open = false); - static Vector> _polypath_offset(const Vector &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type); + static Vector> _polypaths_do_operation(PolyBooleanOperation p_op, const Span &p_polypath_a, const Span &p_polypath_b, bool is_a_open = false); + static Vector> _polypath_offset(const Span &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type); }; #endif // GEOMETRY_H diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp index a0d60ffecde..cdf3f628a8f 100644 --- a/core/math/triangulate.cpp +++ b/core/math/triangulate.cpp @@ -30,7 +30,7 @@ #include "triangulate.h" -real_t Triangulate::get_area(const Vector &contour) { +real_t Triangulate::get_area(const Span &contour) { int n = contour.size(); const Vector2 *c = &contour[0]; @@ -78,7 +78,7 @@ bool Triangulate::is_inside_triangle(real_t Ax, real_t Ay, } } -bool Triangulate::snip(const Vector &p_contour, int u, int v, int w, int n, const Vector &V, bool relaxed) { +bool Triangulate::snip(const Span &p_contour, int u, int v, int w, int n, const Span &V, bool relaxed) { int p; real_t Ax, Ay, Bx, By, Cx, Cy, Px, Py; const Vector2 *contour = &p_contour[0]; @@ -117,7 +117,7 @@ bool Triangulate::snip(const Vector &p_contour, int u, int v, int w, in return true; } -bool Triangulate::triangulate(const Vector &contour, Vector &result) { +bool Triangulate::triangulate(const Span &contour, Vector &result) { /* allocate and initialize list of Vertices in polygon */ int n = contour.size(); diff --git a/core/math/triangulate.h b/core/math/triangulate.h index 6911124ee53..88f23f1e891 100644 --- a/core/math/triangulate.h +++ b/core/math/triangulate.h @@ -41,10 +41,10 @@ class Triangulate { public: // triangulate a contour/polygon, places results in STL vector // as series of triangles. - static bool triangulate(const Vector &contour, Vector &result); + static bool triangulate(const Span &contour, Vector &result); // compute area of a contour/polygon - static real_t get_area(const Vector &contour); + static real_t get_area(const Span &contour); // decide if point Px/Py is inside triangle defined by // (Ax,Ay) (Bx,By) (Cx,Cy) @@ -55,7 +55,7 @@ public: bool include_edges); private: - static bool snip(const Vector &p_contour, int u, int v, int w, int n, const Vector &V, bool relaxed); + static bool snip(const Span &p_contour, int u, int v, int w, int n, const Span &V, bool relaxed); }; #endif // TRIANGULATE_H diff --git a/core/pool_vector.h b/core/pool_vector.h index 36872f7dc74..b4cce5c09f8 100644 --- a/core/pool_vector.h +++ b/core/pool_vector.h @@ -424,6 +424,9 @@ public: return find(p_val) != -1; } + _FORCE_INLINE_ Span span() const { return Span(read().ptr(), (uint32_t)size()); } + _FORCE_INLINE_ operator Span() const { return span(); } + inline int size() const; inline bool empty() const; T get(int p_index) const; diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 41355c98f36..e3cbdf9b527 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -239,7 +239,7 @@ bool CollisionPolygon2D::_edit_use_rect() const { } bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { - return Geometry::is_point_in_polygon(p_point, Variant(polygon)); + return Geometry::is_point_in_polygon(p_point, polygon); } #endif diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 96f8ca7f841..cc7124d9489 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -68,7 +68,7 @@ Rect2 OccluderPolygon2D::_edit_get_rect() const { bool OccluderPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { if (closed) { - return Geometry::is_point_in_polygon(p_point, Variant(polygon)); + return Geometry::is_point_in_polygon(p_point, polygon); } else { const real_t d = LINE_GRAB_WIDTH / 2 + p_tolerance; PoolVector::Read points = polygon.read(); diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index 46d1026d276..2172d0d9d2d 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -73,7 +73,7 @@ bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double if (outline_size < 3) { continue; } - if (Geometry::is_point_in_polygon(p_point, Variant(outline))) { + if (Geometry::is_point_in_polygon(p_point, outline)) { return true; } } From d78e3b050e6ecd8fd46c40bd5309464bbd0c1721 Mon Sep 17 00:00:00 2001 From: Lukas Tenbrink Date: Mon, 13 Oct 2025 12:44:17 +0200 Subject: [PATCH 3/3] Make `LocalVector` -> `Span` conversion function explicit. --- core/local_vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/local_vector.h b/core/local_vector.h index 9c45ee9fe18..bfeb19d2e70 100644 --- a/core/local_vector.h +++ b/core/local_vector.h @@ -295,7 +295,7 @@ public: } } - LocalVector(const Span &p_from) { + explicit LocalVector(const Span &p_from) { resize(p_from.size()); for (U i = 0; i < count; i++) { data[i] = p_from[i];