ソースを参照

Combined TileMapLayer debug quadrant shapes to a surface

Create a combined mesh surface for all mesh faces and mesh lines in the TileMapLayer debug quadrant. Before it created a new mesh surface for each shape crashing into the mesh surface limit of 256 quickly.
smix8 4 ヶ月 前
コミット
33fe4a2d87
1 ファイル変更118 行追加35 行削除
  1. 118 35
      scene/2d/tile_map_layer.cpp

+ 118 - 35
scene/2d/tile_map_layer.cpp

@@ -33,6 +33,7 @@
 #include "core/io/marshalls.h"
 #include "core/math/geometry_2d.h"
 #include "core/math/random_pcg.h"
+#include "core/templates/a_hash_map.h"
 #include "scene/2d/tile_map.h"
 #include "scene/gui/control.h"
 #include "scene/resources/2d/navigation_mesh_source_geometry_data_2d.h"
@@ -1043,9 +1044,7 @@ void TileMapLayer::_physics_draw_quadrant_debug(const RID &p_canvas_item, DebugQ
 	RenderingServer *rs = RenderingServer::get_singleton();
 	PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
 
-	Color debug_collision_color = get_tree()->get_debug_collisions_color();
-	Vector<Color> color;
-	color.push_back(debug_collision_color);
+	const Color &debug_collision_color = get_tree()->get_debug_collisions_color();
 
 	RandomPCG rand;
 	rand.seed(hash_murmur3_one_real(r_debug_quadrant.quadrant_coords.y, hash_murmur3_one_real(r_debug_quadrant.quadrant_coords.x)));
@@ -1061,6 +1060,15 @@ void TileMapLayer::_physics_draw_quadrant_debug(const RID &p_canvas_item, DebugQ
 	Vector2i first_physics_quadrant_coords = _coords_to_quadrant_coords(covered_cell_area.get_position() - Vector2i(1, 1), physics_quadrant_size) + Vector2i(1, 1);
 	Vector2i last_physics_quadrant_coords = _coords_to_quadrant_coords(covered_cell_area.get_end() - Vector2i(1, 1), physics_quadrant_size) + Vector2i(1, 1);
 
+	LocalVector<Vector2> face_vertex_array;
+	LocalVector<Color> face_color_array;
+	LocalVector<int32_t> face_index_array;
+
+	LocalVector<Vector2> line_vertex_array;
+	LocalVector<Color> line_color_array;
+
+	AHashMap<Vector2, int> vertex_map;
+
 	// Arrays to generate a mesh.
 	for (int x = first_physics_quadrant_coords.x; x < last_physics_quadrant_coords.x; x++) {
 		for (int y = first_physics_quadrant_coords.y; y < last_physics_quadrant_coords.y; y++) {
@@ -1074,18 +1082,33 @@ void TileMapLayer::_physics_draw_quadrant_debug(const RID &p_canvas_item, DebugQ
 			const Vector2 debug_quadrant_pos = tile_set->map_to_local(r_debug_quadrant.quadrant_coords * TILE_MAP_DEBUG_QUADRANT_SIZE);
 			Transform2D global_to_debug_quadrant = (get_global_transform() * Transform2D(0, debug_quadrant_pos)).affine_inverse();
 
+			// Clear arrays for new quadrant while keeping allocated memory.
+
+			face_vertex_array.clear();
+			face_color_array.clear();
+			face_index_array.clear();
+
+			line_vertex_array.clear();
+			line_color_array.clear();
+
+			vertex_map.clear();
+
 			for (const KeyValue<PhysicsQuadrant::PhysicsBodyKey, PhysicsQuadrant::PhysicsBodyValue> &kvbody : physics_quadrant->bodies) {
 				const RID &body = kvbody.value.body;
-				Transform2D body_to_quadrant = global_to_debug_quadrant * Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM));
+				int shape_count = ps->body_get_shape_count(body);
+				if (shape_count == 0) {
+					continue;
+				}
+				const Transform2D body_to_quadrant = global_to_debug_quadrant * Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM));
 
-				Color random_variation_color;
-				random_variation_color.set_hsv(
+				Color face_random_variation_color;
+				face_random_variation_color.set_hsv(
 						debug_collision_color.get_h() + rand.random(-1.0, 1.0) * 0.05,
 						debug_collision_color.get_s(),
 						debug_collision_color.get_v() + rand.random(-1.0, 1.0) * 0.1,
 						debug_collision_color.a);
+				const Color line_random_variation_color = face_random_variation_color.lightened(0.2);
 
-				int shape_count = ps->body_get_shape_count(body);
 				for (int shape_index = 0; shape_index < shape_count; shape_index++) {
 					const RID &shape = ps->body_get_shape(body, shape_index);
 					const Transform2D &shape_xform = ps->body_get_shape_transform(body, shape_index);
@@ -1093,48 +1116,108 @@ void TileMapLayer::_physics_draw_quadrant_debug(const RID &p_canvas_item, DebugQ
 
 					if (type == PhysicsServer2D::SHAPE_CONVEX_POLYGON) {
 						PackedVector2Array outline = ps->shape_get_data(shape);
+						const int outline_size = outline.size();
+						if (outline_size < 3) {
+							continue;
+						}
+
+						const Transform2D outline_xform = body_to_quadrant * shape_xform;
+
+						// Adds debug mesh lines.
+
+						Vector2 previous_line_vertex = outline_xform.xform(outline[outline_size - 1]);
+
+						for (int i = 0; i < outline_size; i++) {
+							Vector2 line_vertex = outline_xform.xform(outline[i]);
+
+							line_vertex_array.push_back(previous_line_vertex);
+							line_vertex_array.push_back(line_vertex);
 
-						PackedVector2Array vertex_array;
-						vertex_array.resize(outline.size() + 1);
+							previous_line_vertex = line_vertex;
 
-						PackedColorArray face_color_array;
-						face_color_array.resize(outline.size() + 1);
-						PackedInt32Array face_index_array;
-						face_index_array.resize((outline.size() - 2) * 3);
+							line_color_array.push_back(line_random_variation_color);
+							line_color_array.push_back(line_random_variation_color);
+						}
+
+						// Adds debug mesh faces.
+
+						const Vector2 vertex1 = outline_xform.xform(outline[0]);
+						const Vector2 vertex2 = outline_xform.xform(outline[1]);
+						Vector2 vertex3;
 
-						PackedColorArray line_color_array;
-						line_color_array.resize(outline.size() + 1);
+						int vertex1_index = -1;
+						int vertex2_index = -1;
+						int vertex3_index = -1;
 
-						for (int i = 0; i < outline.size() + 1; i++) {
-							Vector2 vertex = (body_to_quadrant * shape_xform).xform(outline[i % outline.size()]);
-							vertex_array.write[i] = vertex;
-							face_color_array.write[i] = random_variation_color;
-							line_color_array.write[i] = random_variation_color.lightened(0.2);
+						int last_vertex3_index = -1;
+
+						// Find triangle fan anchor vertex1 index.
+						{
+							AHashMap<Vector2, int>::Iterator E = vertex_map.find(vertex1);
+							if (!E) {
+								E = vertex_map.insert(vertex1, vertex_map.size());
+								face_vertex_array.push_back(vertex1);
+								face_color_array.push_back(face_random_variation_color);
+							}
+							vertex1_index = E->value;
 						}
-						for (int i = 0; i < outline.size() - 2; i++) {
-							face_index_array.write[i * 3] = 0;
-							face_index_array.write[i * 3 + 1] = i + 1;
-							face_index_array.write[i * 3 + 2] = i + 2;
+
+						// Find starting vertex2 index.
+						{
+							AHashMap<Vector2, int>::Iterator E = vertex_map.find(vertex2);
+							if (!E) {
+								E = vertex_map.insert(vertex2, vertex_map.size());
+								face_vertex_array.push_back(vertex2);
+								face_color_array.push_back(face_random_variation_color);
+							}
+							vertex2_index = E->value;
 						}
 
-						Array face_mesh_array;
-						face_mesh_array.resize(Mesh::ARRAY_MAX);
-						face_mesh_array[Mesh::ARRAY_VERTEX] = vertex_array;
-						face_mesh_array[Mesh::ARRAY_INDEX] = face_index_array;
-						face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array;
-						rs->mesh_add_surface_from_arrays(r_debug_quadrant.physics_mesh, RS::PRIMITIVE_TRIANGLES, face_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+						// Create mesh triangle face fan from outline vertices using vertex_map indices.
+						for (int i = 1; i < outline_size - 1; i++) {
+							if (i > 1) {
+								vertex2_index = last_vertex3_index;
+							}
 
-						Array line_mesh_array;
-						line_mesh_array.resize(Mesh::ARRAY_MAX);
-						line_mesh_array[Mesh::ARRAY_VERTEX] = vertex_array;
-						line_mesh_array[Mesh::ARRAY_COLOR] = line_color_array;
+							vertex3 = outline_xform.xform(outline[i + 1]);
+
+							{
+								AHashMap<Vector2, int>::Iterator E = vertex_map.find(vertex3);
+								if (!E) {
+									E = vertex_map.insert(vertex3, vertex_map.size());
+									face_vertex_array.push_back(vertex3);
+									face_color_array.push_back(face_random_variation_color);
+								}
+								vertex3_index = E->value;
+								last_vertex3_index = vertex3_index;
+							}
+
+							face_index_array.push_back(vertex1_index);
+							face_index_array.push_back(vertex2_index);
+							face_index_array.push_back(vertex3_index);
+						}
 
-						rs->mesh_add_surface_from_arrays(r_debug_quadrant.physics_mesh, RS::PRIMITIVE_LINE_STRIP, line_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
 					} else {
 						WARN_PRINT("Wrong shape type for a tile, should be SHAPE_CONVEX_POLYGON.");
 					}
 				}
 			}
+
+			if (face_index_array.size() > 2) {
+				Array face_mesh_array;
+				face_mesh_array.resize(Mesh::ARRAY_MAX);
+				face_mesh_array[Mesh::ARRAY_VERTEX] = Vector<Vector2>(face_vertex_array);
+				face_mesh_array[Mesh::ARRAY_INDEX] = Vector<int32_t>(face_index_array);
+				face_mesh_array[Mesh::ARRAY_COLOR] = Vector<Color>(face_color_array);
+				rs->mesh_add_surface_from_arrays(r_debug_quadrant.physics_mesh, RS::PRIMITIVE_TRIANGLES, face_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+
+				Array line_mesh_array;
+				line_mesh_array.resize(Mesh::ARRAY_MAX);
+				line_mesh_array[Mesh::ARRAY_VERTEX] = Vector<Vector2>(line_vertex_array);
+				line_mesh_array[Mesh::ARRAY_COLOR] = Vector<Color>(line_color_array);
+
+				rs->mesh_add_surface_from_arrays(r_debug_quadrant.physics_mesh, RS::PRIMITIVE_LINES, line_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+			}
 		}
 	}
 	rs->canvas_item_add_mesh(p_canvas_item, r_debug_quadrant.physics_mesh, Transform2D());