Pārlūkot izejas kodu

Add Get Center Method for Rect2/Rect2i and AABB.

Anilforextra 3 gadi atpakaļ
vecāks
revīzija
90908cd67d
33 mainītis faili ar 133 papildinājumiem un 56 dzēšanām
  1. 4 0
      core/math/aabb.h
  2. 1 1
      core/math/delaunay_2d.h
  3. 5 1
      core/math/rect2.h
  4. 2 2
      core/math/triangle_mesh.cpp
  5. 3 0
      core/variant/variant_call.cpp
  6. 6 0
      doc/classes/AABB.xml
  7. 6 0
      doc/classes/Rect2.xml
  8. 7 0
      doc/classes/Rect2i.xml
  9. 1 1
      editor/editor_plugin.cpp
  10. 2 2
      editor/editor_spin_slider.cpp
  11. 1 1
      editor/import/scene_import_settings.cpp
  12. 4 4
      editor/plugins/canvas_item_editor_plugin.cpp
  13. 1 1
      editor/plugins/editor_preview_plugins.cpp
  14. 1 1
      editor/plugins/mesh_editor_plugin.cpp
  15. 6 6
      editor/plugins/node_3d_editor_gizmos.cpp
  16. 1 1
      editor/plugins/tiles/atlas_merging_dialog.cpp
  17. 1 1
      editor/plugins/tiles/tile_atlas_view.cpp
  18. 12 12
      editor/plugins/tiles/tile_data_editors.cpp
  19. 4 4
      editor/plugins/tiles/tile_set_atlas_source_editor.cpp
  20. 2 2
      modules/csg/csg.cpp
  21. 10 0
      modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
  22. 10 0
      modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
  23. 13 1
      modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
  24. 1 1
      scene/2d/camera_2d.cpp
  25. 2 2
      scene/3d/gpu_particles_collision_3d.cpp
  26. 2 2
      scene/3d/lightmap_gi.cpp
  27. 4 4
      scene/3d/voxelizer.cpp
  28. 1 1
      servers/physics_3d/shape_3d_sw.cpp
  29. 1 1
      servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
  30. 1 1
      servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
  31. 3 3
      servers/rendering/renderer_scene_cull.cpp
  32. 3 0
      tests/test_aabb.h
  33. 12 0
      tests/test_rect2.h

+ 4 - 0
core/math/aabb.h

@@ -118,6 +118,10 @@ public:
 		return position + size;
 	}
 
+	_FORCE_INLINE_ Vector3 get_center() const {
+		return position + (size * 0.5);
+	}
+
 	operator String() const;
 
 	_FORCE_INLINE_ AABB() {}

+ 1 - 1
core/math/delaunay_2d.h

@@ -101,7 +101,7 @@ public:
 		}
 
 		float delta_max = MAX(rect.size.width, rect.size.height);
-		Vector2 center = rect.position + rect.size * 0.5;
+		Vector2 center = rect.get_center();
 
 		points.push_back(Vector2(center.x - 20 * delta_max, center.y - delta_max));
 		points.push_back(Vector2(center.x, center.y + 20 * delta_max));

+ 5 - 1
core/math/rect2.h

@@ -46,6 +46,8 @@ struct Rect2 {
 
 	real_t get_area() const { return size.width * size.height; }
 
+	_FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5); }
+
 	inline bool intersects(const Rect2 &p_rect, const bool p_include_borders = false) const {
 		if (p_include_borders) {
 			if (position.x > (p_rect.position.x + p_rect.size.width)) {
@@ -259,7 +261,7 @@ struct Rect2 {
 	}
 
 	_FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {
-		Vector2 center = position + size * 0.5;
+		Vector2 center = get_center();
 		int side_plus = 0;
 		int side_minus = 0;
 		Vector2 end = position + size;
@@ -344,6 +346,8 @@ struct Rect2i {
 
 	int get_area() const { return size.width * size.height; }
 
+	_FORCE_INLINE_ Vector2i get_center() const { return position + (size / 2); }
+
 	inline bool intersects(const Rect2i &p_rect) const {
 		if (position.x > (p_rect.position.x + p_rect.size.width)) {
 			return false;

+ 2 - 2
core/math/triangle_mesh.cpp

@@ -76,7 +76,7 @@ int TriangleMesh::_create_bvh(BVH *p_bvh, BVH **p_bb, int p_from, int p_size, in
 	int index = r_max_alloc++;
 	BVH *_new = &p_bvh[index];
 	_new->aabb = aabb;
-	_new->center = aabb.position + aabb.size * 0.5;
+	_new->center = aabb.get_center();
 	_new->face_index = -1;
 	_new->left = left;
 	_new->right = right;
@@ -152,7 +152,7 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces) {
 			bw[i].left = -1;
 			bw[i].right = -1;
 			bw[i].face_index = i;
-			bw[i].center = bw[i].aabb.position + bw[i].aabb.size * 0.5;
+			bw[i].center = bw[i].aabb.get_center();
 		}
 
 		vertices.resize(db.size());

+ 3 - 0
core/variant/variant_call.cpp

@@ -1513,6 +1513,7 @@ static void _register_variant_builtin_methods() {
 
 	/* Rect2 */
 
+	bind_method(Rect2, get_center, sarray(), varray());
 	bind_method(Rect2, get_area, sarray(), varray());
 	bind_method(Rect2, has_no_area, sarray(), varray());
 	bind_method(Rect2, has_point, sarray("point"), varray());
@@ -1529,6 +1530,7 @@ static void _register_variant_builtin_methods() {
 
 	/* Rect2i */
 
+	bind_method(Rect2i, get_center, sarray(), varray());
 	bind_method(Rect2i, get_area, sarray(), varray());
 	bind_method(Rect2i, has_no_area, sarray(), varray());
 	bind_method(Rect2i, has_point, sarray("point"), varray());
@@ -1736,6 +1738,7 @@ static void _register_variant_builtin_methods() {
 	/* AABB */
 
 	bind_method(AABB, abs, sarray(), varray());
+	bind_method(AABB, get_center, sarray(), varray());
 	bind_method(AABB, get_area, sarray(), varray());
 	bind_method(AABB, has_no_area, sarray(), varray());
 	bind_method(AABB, has_no_surface, sarray(), varray());

+ 6 - 0
doc/classes/AABB.xml

@@ -61,6 +61,12 @@
 				Returns the volume of the [AABB].
 			</description>
 		</method>
+		<method name="get_center" qualifiers="const">
+			<return type="Vector3" />
+			<description>
+				Returns the center of the [AABB], which is equal to [member position] + ([member size] / 2).
+			</description>
+		</method>
 		<method name="get_endpoint" qualifiers="const">
 			<return type="Vector3" />
 			<argument index="0" name="idx" type="int" />

+ 6 - 0
doc/classes/Rect2.xml

@@ -78,6 +78,12 @@
 				Returns the area of the [Rect2].
 			</description>
 		</method>
+		<method name="get_center" qualifiers="const">
+			<return type="Vector2" />
+			<description>
+				Returns the center of the [Rect2], which is equal to [member position] + ([member size] / 2).
+			</description>
+		</method>
 		<method name="grow" qualifiers="const">
 			<return type="Rect2" />
 			<argument index="0" name="amount" type="float" />

+ 7 - 0
doc/classes/Rect2i.xml

@@ -76,6 +76,13 @@
 				Returns the area of the [Rect2i].
 			</description>
 		</method>
+		<method name="get_center" qualifiers="const">
+			<return type="Vector2i" />
+			<description>
+				Returns the center of the [Rect2i], which is equal to [member position] + ([member size] / 2).
+				If [member size] is an odd number, the returned center value will be rounded towards [member position].
+			</description>
+		</method>
 		<method name="grow" qualifiers="const">
 			<return type="Rect2i" />
 			<argument index="0" name="amount" type="int" />

+ 1 - 1
editor/editor_plugin.cpp

@@ -104,7 +104,7 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh
 		RS::get_singleton()->instance_set_transform(inst, mesh_xform);
 
 		AABB aabb = mesh->get_aabb();
-		Vector3 ofs = aabb.position + aabb.size * 0.5;
+		Vector3 ofs = aabb.get_center();
 		aabb.position -= ofs;
 		Transform3D xform;
 		xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI / 6);

+ 2 - 2
editor/editor_spin_slider.cpp

@@ -328,7 +328,7 @@ void EditorSpinSlider::_draw_spin_slider() {
 		Rect2 grabber_rect = Rect2(ofs + gofs, svofs + 1, grabber_w, 2 * EDSCALE);
 		draw_rect(grabber_rect, c);
 
-		grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.position + grabber_rect.size * 0.5;
+		grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.get_center();
 
 		bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !(value_input_popup && value_input_popup->is_visible());
 		if (grabber->is_visible() != display_grabber) {
@@ -354,7 +354,7 @@ void EditorSpinSlider::_draw_spin_slider() {
 			Vector2 scale = get_global_transform_with_canvas().get_scale();
 			grabber->set_scale(scale);
 			grabber->set_size(Size2(0, 0));
-			grabber->set_position(get_global_position() + (grabber_rect.position + grabber_rect.size * 0.5 - grabber->get_size() * 0.5) * scale);
+			grabber->set_position(get_global_position() + (grabber_rect.get_center() - grabber->get_size() * 0.5) * scale);
 
 			if (mousewheel_over_grabber) {
 				Input::get_singleton()->warp_mouse_position(grabber->get_position() + grabber_rect.size);

+ 1 - 1
editor/import/scene_import_settings.cpp

@@ -434,7 +434,7 @@ void SceneImportSettings::_update_camera() {
 		}
 	}
 
-	Vector3 center = camera_aabb.position + camera_aabb.size * 0.5;
+	Vector3 center = camera_aabb.get_center();
 	float camera_size = camera_aabb.get_longest_axis_size();
 
 	camera->set_orthogonal(camera_size * zoom, 0.0001, camera_size * 2);

+ 4 - 4
editor/plugins/canvas_item_editor_plugin.cpp

@@ -387,7 +387,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig
 		// Self center
 		if ((is_snap_active && snap_node_center && (p_modes & SNAP_NODE_CENTER)) || (p_forced_modes & SNAP_NODE_CENTER)) {
 			if (p_self_canvas_item->_edit_use_rect()) {
-				Point2 center = p_self_canvas_item->get_global_transform_with_canvas().xform(p_self_canvas_item->_edit_get_rect().get_position() + p_self_canvas_item->_edit_get_rect().get_size() / 2.0);
+				Point2 center = p_self_canvas_item->get_global_transform_with_canvas().xform(p_self_canvas_item->_edit_get_rect().get_center());
 				_snap_if_closer_point(p_target, output, snap_target, center, SNAP_TARGET_SELF, rotation);
 			} else {
 				Point2 position = p_self_canvas_item->get_global_transform_with_canvas().xform(Point2());
@@ -525,7 +525,7 @@ Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_li
 
 	// Handles the first element
 	CanvasItem *canvas_item = p_list.front()->get();
-	Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2());
+	Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().get_center()), Size2());
 
 	// Expand with the other ones
 	for (CanvasItem *canvas_item2 : p_list) {
@@ -564,7 +564,7 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c
 		Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform();
 		Rect2 rect = canvas_item->_edit_get_rect();
 		if (r_first) {
-			r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2());
+			r_rect = Rect2(xform.xform(rect.get_center()), Size2());
 			r_first = false;
 		}
 		r_rect.expand_to(xform.xform(rect.position));
@@ -4896,7 +4896,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
 	};
 
 	if (p_op == VIEW_CENTER_TO_SELECTION) {
-		center = rect.position + rect.size / 2;
+		center = rect.get_center();
 		Vector2 offset = viewport->get_size() / 2 - editor->get_scene_root()->get_global_canvas_transform().xform(center);
 		view_offset.x -= Math::round(offset.x / zoom);
 		view_offset.y -= Math::round(offset.y / zoom);

+ 1 - 1
editor/plugins/editor_preview_plugins.cpp

@@ -718,7 +718,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
 	RS::get_singleton()->instance_set_base(mesh_instance, mesh->get_rid());
 
 	AABB aabb = mesh->get_aabb();
-	Vector3 ofs = aabb.position + aabb.size * 0.5;
+	Vector3 ofs = aabb.get_center();
 	aabb.position -= ofs;
 	Transform3D xform;
 	xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI * 0.125);

+ 1 - 1
editor/plugins/mesh_editor_plugin.cpp

@@ -80,7 +80,7 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) {
 	_update_rotation();
 
 	AABB aabb = mesh->get_aabb();
-	Vector3 ofs = aabb.position + aabb.size * 0.5;
+	Vector3 ofs = aabb.get_center();
 	float m = aabb.get_longest_axis_size();
 	if (m != 0) {
 		m = 1.0 / m;

+ 6 - 6
editor/plugins/node_3d_editor_gizmos.cpp

@@ -2652,7 +2652,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p
 
 	Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
 
-	Vector3 ofs = aabb.position + aabb.size * 0.5;
+	Vector3 ofs = aabb.get_center();
 
 	Vector3 axis;
 	axis[p_id] = 1.0;
@@ -2728,7 +2728,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 		handles.push_back(ax);
 	}
 
-	Vector3 center = aabb.position + aabb.size * 0.5;
+	Vector3 center = aabb.get_center();
 	for (int i = 0; i < 3; i++) {
 		Vector3 ax;
 		ax[i] = 1.0;
@@ -2744,7 +2744,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 
 	if (p_gizmo->is_selected()) {
 		Ref<Material> solid_material = get_material("visibility_notifier_solid_material", p_gizmo);
-		p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
+		p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center());
 	}
 
 	p_gizmo->add_handles(handles, get_material("handles"));
@@ -2843,7 +2843,7 @@ void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int
 
 	Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
 
-	Vector3 ofs = aabb.position + aabb.size * 0.5;
+	Vector3 ofs = aabb.get_center();
 
 	Vector3 axis;
 	axis[p_id] = 1.0;
@@ -2919,7 +2919,7 @@ void GPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 		handles.push_back(ax);
 	}
 
-	Vector3 center = aabb.position + aabb.size * 0.5;
+	Vector3 center = aabb.get_center();
 	for (int i = 0; i < 3; i++) {
 		Vector3 ax;
 		ax[i] = 1.0;
@@ -2935,7 +2935,7 @@ void GPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 
 	if (p_gizmo->is_selected()) {
 		Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo);
-		p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
+		p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center());
 	}
 
 	p_gizmo->add_handles(handles, get_material("handles"));

+ 1 - 1
editor/plugins/tiles/atlas_merging_dialog.cpp

@@ -99,7 +99,7 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla
 				if (dst_rect_wide.get_end().x > output_image->get_width() || dst_rect_wide.get_end().y > output_image->get_height()) {
 					output_image->crop(MAX(dst_rect_wide.get_end().x, output_image->get_width()), MAX(dst_rect_wide.get_end().y, output_image->get_height()));
 				}
-				output_image->blit_rect(atlas_source->get_texture()->get_image(), src_rect, (dst_rect_wide.get_position() + dst_rect_wide.get_end()) / 2 - src_rect.size / 2);
+				output_image->blit_rect(atlas_source->get_texture()->get_image(), src_rect, dst_rect_wide.get_center() - src_rect.size / 2);
 			}
 
 			// Compute the atlas offset.

+ 1 - 1
editor/plugins/tiles/tile_atlas_view.cpp

@@ -330,7 +330,7 @@ void TileAtlasView::_draw_base_tiles_shape_grid() {
 
 		// Draw only if the tile shape fits in the texture region
 		Transform2D tile_xform;
-		tile_xform.set_origin(texture_region.position + texture_region.size / 2 + in_tile_base_offset);
+		tile_xform.set_origin(texture_region.get_center() + in_tile_base_offset);
 		tile_xform.set_scale(tile_shape_size);
 		tile_set->draw_tile_shape(base_tiles_shape_grid, tile_xform, grid_color);
 	}

+ 12 - 12
editor/plugins/tiles/tile_data_editors.cpp

@@ -1495,7 +1495,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
 			TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, 0));
 			int terrain_set = tile_data->get_terrain_set();
 			Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(hovered_coords);
-			Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, 0);
+			Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, 0);
 
 			if (terrain_set >= 0 && terrain_set == int(dummy_object->get("terrain_set"))) {
 				// Draw hovered bit.
@@ -1540,7 +1540,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
 				// Text
 				p_canvas_item->draw_set_transform_matrix(Transform2D());
 				Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
-				Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+				Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
 
 				Color color = Color(1, 1, 1);
 				String text;
@@ -1632,7 +1632,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
 			Vector2i coords = E->get().get_atlas_coords();
 
 			Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
-			Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+			Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
 
 			for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
 				TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
@@ -1668,7 +1668,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
 			TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, hovered_alternative));
 			int terrain_set = tile_data->get_terrain_set();
 			Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(hovered_coords, hovered_alternative);
-			Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, hovered_alternative);
+			Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, hovered_alternative);
 
 			if (terrain_set == int(dummy_object->get("terrain_set"))) {
 				// Draw hovered bit.
@@ -1715,7 +1715,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
 					// Text
 					p_canvas_item->draw_set_transform_matrix(Transform2D());
 					Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
-					Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+					Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
 
 					Color color = Color(1, 1, 1);
 					String text;
@@ -1796,7 +1796,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
 
 						// Set the terrains bits.
 						Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
-						Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+						Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
 						for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
 							TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
 							if (tile_data->is_valid_peering_bit_terrain(bit)) {
@@ -1824,7 +1824,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
 						TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
 						int terrain_set = tile_data->get_terrain_set();
 						Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
-						Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+						Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
 						dummy_object->set("terrain_set", terrain_set);
 						dummy_object->set("terrain", -1);
 						for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
@@ -1922,7 +1922,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
 
 								// Set the terrain bit.
 								Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
-								Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+								Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
 
 								for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
 									TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
@@ -2055,7 +2055,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
 							TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
 							if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
 								Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
-								Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+								Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
 
 								Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
 								for (int j = 0; j < polygon.size(); j++) {
@@ -2138,7 +2138,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
 
 					// Set the terrains bits.
 					Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
-					Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+					Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
 					for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
 						TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
 						if (tile_data->is_valid_peering_bit_terrain(bit)) {
@@ -2167,7 +2167,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
 						TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
 						int terrain_set = tile_data->get_terrain_set();
 						Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
-						Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+						Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
 						dummy_object->set("terrain_set", terrain_set);
 						dummy_object->set("terrain", -1);
 						for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
@@ -2242,7 +2242,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
 
 							// Set the terrain bit.
 							Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
-							Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+							Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
 							for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
 								TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
 								if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {

+ 4 - 4
editor/plugins/tiles/tile_set_atlas_source_editor.cpp

@@ -1638,7 +1638,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() {
 		for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
 			Vector2i coords = tile_set_atlas_source->get_tile_id(i);
 			Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(coords);
-			Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+			Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
 
 			Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
 			xform.translate(position);
@@ -1661,7 +1661,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() {
 					continue;
 				}
 				Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(E->get().tile);
-				Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(E->get().tile, 0);
+				Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(E->get().tile, 0);
 
 				Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
 				xform.translate(position);
@@ -1805,7 +1805,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
 					continue;
 				}
 				Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
-				Vector2 position = (rect.get_position() + rect.get_end()) / 2;
+				Vector2 position = rect.get_center();
 
 				Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
 				xform.translate(position);
@@ -1829,7 +1829,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
 					continue;
 				}
 				Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E->get().tile, E->get().alternative);
-				Vector2 position = (rect.get_position() + rect.get_end()) / 2;
+				Vector2 position = rect.get_center();
 
 				Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
 				xform.translate(position);

+ 2 - 2
modules/csg/csg.cpp

@@ -517,7 +517,7 @@ int CSGBrushOperation::MeshMerge::_create_bvh(FaceBVH *facebvhptr, FaceBVH **fac
 	int index = r_max_alloc++;
 	FaceBVH *_new = &facebvhptr[index];
 	_new->aabb = aabb;
-	_new->center = aabb.position + aabb.size * 0.5;
+	_new->center = aabb.get_center();
 	_new->face = -1;
 	_new->left = left;
 	_new->right = right;
@@ -678,7 +678,7 @@ void CSGBrushOperation::MeshMerge::mark_inside_faces() {
 		facebvh[i].aabb.position = points[faces[i].points[0]];
 		facebvh[i].aabb.expand_to(points[faces[i].points[1]]);
 		facebvh[i].aabb.expand_to(points[faces[i].points[2]]);
-		facebvh[i].center = facebvh[i].aabb.position + facebvh[i].aabb.size * 0.5;
+		facebvh[i].center = facebvh[i].aabb.get_center();
 		facebvh[i].aabb.grow_by(vertex_snap);
 		facebvh[i].next = -1;
 

+ 10 - 0
modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs

@@ -66,6 +66,16 @@ namespace Godot
             return new AABB(topLeft, _size.Abs());
         }
 
+        /// <summary>
+        /// Returns the center of the <see cref="AABB"/>, which is equal
+        /// to <see cref="Position"/> + (<see cref="Size"/> / 2).
+        /// </summary>
+        /// <returns>The center.</returns>
+        public Vector3 GetCenter()
+        {
+            return _position + (_size * 0.5f);
+        }
+
         /// <summary>
         /// Returns <see langword="true"/> if this <see cref="AABB"/> completely encloses another one.
         /// </summary>

+ 10 - 0
modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs

@@ -164,6 +164,16 @@ namespace Godot
             return _size.x * _size.y;
         }
 
+        /// <summary>
+        /// Returns the center of the <see cref="Rect2"/>, which is equal
+        /// to <see cref="Position"/> + (<see cref="Size"/> / 2).
+        /// </summary>
+        /// <returns>The center.</returns>
+        public Vector2 GetCenter()
+        {
+            return _position + (_size * 0.5f);
+        }
+
         /// <summary>
         /// Returns a copy of the <see cref="Rect2"/> grown by the specified amount
         /// on all sides.

+ 13 - 1
modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs

@@ -151,7 +151,7 @@ namespace Godot
         }
 
         /// <summary>
-        /// Returns the area of the <see cref="Rect2"/>.
+        /// Returns the area of the <see cref="Rect2i"/>.
         /// </summary>
         /// <returns>The area.</returns>
         public int GetArea()
@@ -159,6 +159,18 @@ namespace Godot
             return _size.x * _size.y;
         }
 
+        /// <summary>
+        /// Returns the center of the <see cref="Rect2i"/>, which is equal
+        /// to <see cref="Position"/> + (<see cref="Size"/> / 2).
+        /// If <see cref="Size"/> is an odd number, the returned center
+        /// value will be rounded towards <see cref="Position"/>.
+        /// </summary>
+        /// <returns>The center.</returns>
+        public Vector2i GetCenter()
+        {
+            return _position + (_size / 2);
+        }
+
         /// <summary>
         /// Returns a copy of the <see cref="Rect2i"/> grown by the specified amount
         /// on all sides.

+ 1 - 1
scene/2d/camera_2d.cpp

@@ -198,7 +198,7 @@ Transform2D Camera2D::get_camera_transform() {
 		screen_rect.position += offset;
 	}
 
-	camera_screen_center = screen_rect.position + screen_rect.size * 0.5;
+	camera_screen_center = screen_rect.get_center();
 
 	Transform2D xform;
 	xform.scale_basis(zoom);

+ 2 - 2
scene/3d/gpu_particles_collision_3d.cpp

@@ -420,7 +420,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() {
 					}
 
 					//test against original bounds
-					if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) {
+					if (!Geometry3D::triangle_box_overlap(aabb.get_center(), aabb.size * 0.5, face.vertex)) {
 						continue;
 					}
 
@@ -438,7 +438,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() {
 					}
 
 					//test against original bounds
-					if (!Geometry3D::triangle_box_overlap(aabb.position + aabb.size * 0.5, aabb.size * 0.5, face.vertex)) {
+					if (!Geometry3D::triangle_box_overlap(aabb.get_center(), aabb.size * 0.5, face.vertex)) {
 						continue;
 					}
 

+ 2 - 2
scene/3d/lightmap_gi.cpp

@@ -467,7 +467,7 @@ int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const Loc
 				}
 			}
 			if (i == 0) {
-				centers.push_back(bounds.position + bounds.size * 0.5);
+				centers.push_back(bounds.get_center());
 			} else {
 				bounds_all.merge_with(bounds);
 			}
@@ -555,7 +555,7 @@ void LightmapGI::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cel
 		subcell.position = Vector3(pos) * p_cell_size;
 		subcell.size = Vector3(half_size, half_size, half_size) * p_cell_size;
 
-		if (!Geometry3D::triangle_box_overlap(subcell.position + subcell.size * 0.5, subcell.size * 0.5, p_triangle)) {
+		if (!Geometry3D::triangle_box_overlap(subcell.get_center(), subcell.size * 0.5, p_triangle)) {
 			continue;
 		}
 

+ 4 - 4
scene/3d/voxelizer.cpp

@@ -173,7 +173,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co
 			//could not in any way get texture information.. so use closest point to center
 
 			Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]);
-			Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5);
+			Vector3 inters = f.get_closest_point_to(p_aabb.get_center());
 
 			Vector3 lnormal;
 			Vector2 uv;
@@ -434,7 +434,7 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
 				}
 
 				//test against original bounds
-				if (!Geometry3D::triangle_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) {
+				if (!Geometry3D::triangle_box_overlap(original_bounds.get_center(), original_bounds.size * 0.5, vtxs)) {
 					continue;
 				}
 				//plot
@@ -466,7 +466,7 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
 				}
 
 				//test against original bounds
-				if (!Geometry3D::triangle_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) {
+				if (!Geometry3D::triangle_box_overlap(original_bounds.get_center(), original_bounds.size * 0.5, vtxs)) {
 					continue;
 				}
 				//plot face
@@ -885,7 +885,7 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
 
 void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx) {
 	if (p_level == cell_subdiv - 1) {
-		Vector3 center = p_aabb.position + p_aabb.size * 0.5;
+		Vector3 center = p_aabb.get_center();
 		Transform3D xform;
 		xform.origin = center;
 		xform.basis.scale(p_aabb.size * 0.5);

+ 1 - 1
servers/physics_3d/shape_3d_sw.cpp

@@ -1576,7 +1576,7 @@ void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_back
 		Face3 face(facesr[i * 3 + 0], facesr[i * 3 + 1], facesr[i * 3 + 2]);
 
 		bvh_arrayw[i].aabb = face.get_aabb();
-		bvh_arrayw[i].center = bvh_arrayw[i].aabb.position + bvh_arrayw[i].aabb.size * 0.5;
+		bvh_arrayw[i].center = bvh_arrayw[i].aabb.get_center();
 		bvh_arrayw[i].face_index = i;
 		facesw[i].indices[0] = i * 3 + 0;
 		facesw[i].indices[1] = i * 3 + 1;

+ 1 - 1
servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp

@@ -1621,7 +1621,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh
 
 	Vector2 light_dir = p_light_xform.elements[1].normalized();
 
-	Vector2 center = p_clip_rect.position + p_clip_rect.size * 0.5;
+	Vector2 center = p_clip_rect.get_center();
 
 	float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center));
 

+ 1 - 1
servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp

@@ -2575,7 +2575,7 @@ void RendererSceneGIRD::VoxelGIInstance::update(bool p_update_light_instances, c
 				Vector3 render_dir = render_z[j];
 				Vector3 up_dir = render_up[j];
 
-				Vector3 center = aabb.position + aabb.size * 0.5;
+				Vector3 center = aabb.get_center();
 				Transform3D xform;
 				xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir);
 

+ 3 - 3
servers/rendering/renderer_scene_cull.cpp

@@ -1286,7 +1286,7 @@ void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_ins
 		vd.range_end = p_instance->visibility_range_end;
 		vd.range_begin_margin = p_instance->visibility_range_begin_margin;
 		vd.range_end_margin = p_instance->visibility_range_end_margin;
-		vd.position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f;
+		vd.position = p_instance->transformed_aabb.get_center();
 		vd.array_index = p_instance->array_index;
 
 		InstanceGeometryData *geom_data = static_cast<InstanceGeometryData *>(p_instance->base_data);
@@ -1636,7 +1636,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
 	}
 
 	if (p_instance->visibility_index != -1) {
-		p_instance->scenario->instance_visibility[p_instance->visibility_index].position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f;
+		p_instance->scenario->instance_visibility[p_instance->visibility_index].position = p_instance->transformed_aabb.get_center();
 	}
 
 	//move instance and repair
@@ -1851,7 +1851,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
 		}
 
 		Transform3D to_bounds = lightmap->transform.affine_inverse();
-		Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center
+		Vector3 center = p_instance->transform.xform(p_instance->aabb.get_center()); //use aabb center
 
 		Vector3 lm_pos = to_bounds.xform(center);
 

+ 3 - 0
tests/test_aabb.h

@@ -65,6 +65,9 @@ TEST_CASE("[AABB] Basic getters") {
 	CHECK_MESSAGE(
 			aabb.get_end().is_equal_approx(Vector3(2.5, 7, 3.5)),
 			"get_end() should return the expected value.");
+	CHECK_MESSAGE(
+			aabb.get_center().is_equal_approx(Vector3(0.5, 4.5, 0.5)),
+			"get_center() should return the expected value.");
 }
 
 TEST_CASE("[AABB] Basic setters") {

+ 12 - 0
tests/test_rect2.h

@@ -76,6 +76,12 @@ TEST_CASE("[Rect2] Basic getters") {
 	CHECK_MESSAGE(
 			rect.get_end().is_equal_approx(Vector2(1280, 820)),
 			"get_end() should return the expected value.");
+	CHECK_MESSAGE(
+			rect.get_center().is_equal_approx(Vector2(640, 460)),
+			"get_center() should return the expected value.");
+	CHECK_MESSAGE(
+			Rect2(0, 100, 1281, 721).get_center().is_equal_approx(Vector2(640.5, 460.5)),
+			"get_center() should return the expected value.");
 }
 
 TEST_CASE("[Rect2] Basic setters") {
@@ -288,6 +294,12 @@ TEST_CASE("[Rect2i] Basic getters") {
 	CHECK_MESSAGE(
 			rect.get_end() == Vector2i(1280, 820),
 			"get_end() should return the expected value.");
+	CHECK_MESSAGE(
+			rect.get_center() == Vector2i(640, 460),
+			"get_center() should return the expected value.");
+	CHECK_MESSAGE(
+			Rect2i(0, 100, 1281, 721).get_center() == Vector2i(640, 460),
+			"get_center() should return the expected value.");
 }
 
 TEST_CASE("[Rect2i] Basic setters") {