diff --git a/.sconsign.dblite b/.sconsign.dblite index 19a9b2d..dcd2883 100644 Binary files a/.sconsign.dblite and b/.sconsign.dblite differ diff --git a/demo/assets/scripts/environment/destructable/destructable_wall.gd b/demo/assets/scripts/environment/destructable/destructable_wall.gd index e5a4603..8a22a0d 100644 --- a/demo/assets/scripts/environment/destructable/destructable_wall.gd +++ b/demo/assets/scripts/environment/destructable/destructable_wall.gd @@ -13,15 +13,32 @@ enum ExtrudeDirection { @export var extrusion_direction: ExtrudeDirection @export var depth: float = 0.1 @export var depth_position_offset: Vector3 = Vector3.ZERO - +@export_category("User Defined Values") @export var edge_non_fracture: float = 0.1 -@onready var parentNode = get_node("..") + +var parentNode +var inner_rtree: RectangleTree var outer_polygon: PackedVector2Array -var inner_polygons: Array[PackedVector2Array] +var inner_polygons: Holes var static_body: StaticBody3D +func _ready() -> void: + if Engine.is_editor_hint(): + return + + parentNode = get_node("..") + inner_polygons = Holes.new() + inner_rtree = RectangleTree.new() + outer_polygon = verts2d + _draw() + +func _exit_tree() -> void: + if Engine.is_editor_hint(): + return + inner_rtree.free() + func _func_godot_apply_properties(entity_properties: Dictionary) -> void: meshInstance3d = _find_mesh_body() var verticies = meshInstance3d.mesh.surface_get_arrays(0)[Mesh.ARRAY_VERTEX] @@ -75,20 +92,12 @@ func _func_godot_apply_properties(entity_properties: Dictionary) -> void: var outer_boudary = Geometry2D.convex_hull(verts_2d) verts2d = outer_boudary -func _ready() -> void: - if Engine.is_editor_hint(): - return - - outer_polygon = verts2d - _draw() - func _draw(): - var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons) + var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons.get_holes()) var vectors = [] vectors.append_array(outer_polygon) - for ip in inner_polygons: - vectors.append_array(ip) + vectors.append_array(inner_polygons.get_hole_verticies()) var meshGenerator = GeoPolyMesh.new(vector_indexes, vectors, extrusion_direction, depth) var commited_mesh = meshGenerator.commit_mesh(meshInstance3d.get_active_material(0)) @@ -101,24 +110,29 @@ func _draw(): static_body = _find_static_body() func _re_draw(): - meshInstance3d.remove_child(static_body) - static_body.queue_free() - - var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons) + var vector_indexes = GeoPolyTriangulization.triangulate(outer_polygon, inner_polygons.get_holes()) var vectors = [] vectors.append_array(outer_polygon) - for ip in inner_polygons: - vectors.append_array(ip) + vectors.append_array(inner_polygons.get_hole_verticies()) + WorkerThreadPool.add_task(_generate_mesh.bind(vector_indexes, vectors)) + +func _deffered_draw(mesh: Mesh, task_id: int): + if task_id: + WorkerThreadPool.wait_for_task_completion(task_id) + meshInstance3d.remove_child(static_body) + static_body.queue_free() + meshInstance3d.mesh = mesh + meshInstance3d.create_trimesh_collision() + static_body = _find_static_body() + +func _generate_mesh(vector_indexes: PackedInt32Array, vectors: PackedVector2Array): var meshGenerator = GeoPolyMesh.new(vector_indexes, vectors, extrusion_direction, depth) var commited_mesh = meshGenerator.commit_mesh(meshInstance3d.get_active_material(0)) meshGenerator.free() - meshInstance3d.mesh = commited_mesh - meshInstance3d.create_trimesh_collision() - static_body = _find_static_body() - + self.call_deferred("_deffered_draw", commited_mesh, WorkerThreadPool.get_caller_task_id()) func hit(position: Vector3): var cutter = Cutter.circleCutter() @@ -134,13 +148,18 @@ func hit(position: Vector3): # translate the cutter var hole_vectors = Transform2D(0, hole_vector2_offset) * cutter - var draw = _add_hole(hole_vectors) + + var rtree_search = [] + for hv in hole_vectors: + rtree_search.append_array(inner_rtree.query(hv)) + + var draw = _add_hole(hole_vectors, rtree_search) if draw: _re_draw() -func _add_hole(new_hole: PackedVector2Array) -> bool: - var values_to_remove = [] +func _add_hole(new_hole: PackedVector2Array, holes_id: PackedInt32Array) -> bool: + var ids_to_remove = [] # validate that the hole is valid var boundary_polygon = Geometry2D.offset_polygon(outer_polygon, -edge_non_fracture) @@ -150,24 +169,28 @@ func _add_hole(new_hole: PackedVector2Array) -> bool: return false var merged: PackedVector2Array = boundary_hole[0] - for index in range(len(self.inner_polygons)): - var result = Geometry2D.merge_polygons(merged, self.inner_polygons[index]) + + for id in holes_id: + var result = Geometry2D.merge_polygons(merged, inner_polygons.get_hole(id).vectors) if len(result) == 1: merged = result[0] - values_to_remove.append(self.inner_polygons[index]) + ids_to_remove.append(id) elif len(result) > 1: # need to check that they have no overlapping area if they do clip var overlap = Geometry2D.intersect_polygons(result[0], result[1]) if len(overlap) != 0: merged = Geometry2D.clip_polygons(result[0], result[1])[0] - values_to_remove.append(self.inner_polygons[index]) + ids_to_remove.append(id) - for i in values_to_remove: - inner_polygons.erase(i) + for id in ids_to_remove: + inner_rtree.remove(id) + inner_polygons.remove_hole(id) - inner_polygons.append(merged) + var hole = inner_polygons.add_hole(merged) + var bound_rect = UTIL.get_bounding_rect(merged) + inner_rtree.add(bound_rect.position, bound_rect.end, hole.hole_id) return true diff --git a/demo/assets/scripts/environment/destructable/holes.gd b/demo/assets/scripts/environment/destructable/holes.gd new file mode 100644 index 0000000..b970b20 --- /dev/null +++ b/demo/assets/scripts/environment/destructable/holes.gd @@ -0,0 +1,34 @@ +extends RefCounted + +class_name Holes + +var holes: Dictionary[int, Hole] +var counter: int = 0 + +func _init() -> void: + self.holes = {} + +func add_hole(vectors: PackedVector2Array) -> Hole: + var hole = Hole.new(counter, vectors) + self.holes[counter] = hole + counter += 1 + + return hole + +func remove_hole(hole_id: int): + self.holes.erase(hole_id) + +func get_hole(hole_id: int) -> Hole: + return self.holes[hole_id] + +func get_hole_verticies() -> PackedVector2Array: + var return_val: PackedVector2Array = [] + for hole in holes.values(): + return_val.append_array(hole.vectors) + return return_val + +func get_holes() -> Array[PackedVector2Array]: + var return_val: Array[PackedVector2Array] = [] + for hole in holes.values(): + return_val.append(hole.vectors) + return return_val diff --git a/demo/assets/scripts/environment/destructable/holes.gd.uid b/demo/assets/scripts/environment/destructable/holes.gd.uid new file mode 100644 index 0000000..b0d46e0 --- /dev/null +++ b/demo/assets/scripts/environment/destructable/holes.gd.uid @@ -0,0 +1 @@ +uid://dt73l1q8fgdyo diff --git a/demo/assets/scripts/environment/destructable/resource/hole.gd b/demo/assets/scripts/environment/destructable/resource/hole.gd new file mode 100644 index 0000000..f55770f --- /dev/null +++ b/demo/assets/scripts/environment/destructable/resource/hole.gd @@ -0,0 +1,10 @@ +extends Resource + +class_name Hole + +var hole_id: int +var vectors: PackedVector2Array + +func _init(hole_id: int, vectors: PackedVector2Array): + self.hole_id = hole_id + self.vectors = vectors diff --git a/demo/assets/scripts/environment/destructable/resource/hole.gd.uid b/demo/assets/scripts/environment/destructable/resource/hole.gd.uid new file mode 100644 index 0000000..8670056 --- /dev/null +++ b/demo/assets/scripts/environment/destructable/resource/hole.gd.uid @@ -0,0 +1 @@ +uid://cqtnb878sls4b diff --git a/demo/assets/scripts/environment/destructable/util.gd b/demo/assets/scripts/environment/destructable/util.gd index 8f6223a..f8119fd 100644 --- a/demo/assets/scripts/environment/destructable/util.gd +++ b/demo/assets/scripts/environment/destructable/util.gd @@ -14,3 +14,14 @@ static func chunk_array(arr: Array, chunk_size: int) -> Array: static func vector2_to_vector3(v: Vector2) -> Vector3: return Vector3(v.x, v.y, 0) + +static func get_bounding_rect(vectors: PackedVector2Array) -> Rect2: + if vectors.is_empty(): + return Rect2() + + var rect := Rect2(vectors[0], Vector2.ZERO) # Initialize with the first point + for point in vectors: + rect = rect.expand(point) + + # The 'position' of the Rect2 will be the minimum corner + return rect diff --git a/demo/bin/libgtriangulation.linux.template_debug.x86_64.so b/demo/bin/libgtriangulation.linux.template_debug.x86_64.so index 57eb8fd..5816240 100755 Binary files a/demo/bin/libgtriangulation.linux.template_debug.x86_64.so and b/demo/bin/libgtriangulation.linux.template_debug.x86_64.so differ diff --git a/src/rectangletree.os b/src/rectangletree.os index 72b30f4..84dc24a 100644 Binary files a/src/rectangletree.os and b/src/rectangletree.os differ diff --git a/src/register_types.os b/src/register_types.os index 82085ea..3c7833c 100644 Binary files a/src/register_types.os and b/src/register_types.os differ diff --git a/src/triangulization.os b/src/triangulization.os index 7c44541..5cdb11f 100644 Binary files a/src/triangulization.os and b/src/triangulization.os differ