diff --git a/.sconsign.dblite b/.sconsign.dblite index 0597586..a598324 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 6d8182b..a606c6a 100644 --- a/demo/assets/scripts/environment/destructable/destructable_wall.gd +++ b/demo/assets/scripts/environment/destructable/destructable_wall.gd @@ -10,10 +10,11 @@ enum ExtrudeDirection { @export_category("TrechBroom Generated Values") @export var verts2d: PackedVector2Array @export var meshInstance3d: MeshInstance3D -@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_category("TrechBroom User Values") +@export var extrusion_direction: ExtrudeDirection +@export var hole_proximity: float @export var edge_non_fracture: float = 0.1 var parentNode @@ -44,6 +45,8 @@ func _func_godot_apply_properties(entity_properties: Dictionary) -> void: var verticies = meshInstance3d.mesh.surface_get_arrays(0)[Mesh.ARRAY_VERTEX] extrusion_direction = entity_properties["extrude_direction"] + hole_proximity = entity_properties["hole_proximity"] + edge_non_fracture = entity_properties["edge_non_fractured"] var depth_min: float var depth_max: float @@ -192,6 +195,24 @@ func _add_hole(new_hole: PackedVector2Array) -> bool: var bound_rect = UTIL.get_bounding_rect(merged) inner_rtree.add(bound_rect.position, bound_rect.end, hole.hole_id) + var hole_prox_boundary = bound_rect.grow(hole.area * 4) + var prox_holes_ids = inner_rtree.query_rect(hole_prox_boundary.position, hole_prox_boundary.end) + + # any holes that are close in proximity convex hull + if len(prox_holes_ids) <= 1: # needs to be length 2 or more because it will always return the hole just created + return true + + var proxmity_hole_vectors = [] + for id in prox_holes_ids: + proxmity_hole_vectors.append_array(inner_polygons.get_hole(id).vectors) + inner_rtree.remove(id) + inner_polygons.remove_hole(id) + + var convex_vectors = Geometry2D.convex_hull(proxmity_hole_vectors) + hole = inner_polygons.add_hole(convex_vectors) + bound_rect = UTIL.get_bounding_rect(convex_vectors) + inner_rtree.add(bound_rect.position, bound_rect.end, hole.hole_id) + return true func _find_static_body(): diff --git a/demo/assets/scripts/environment/destructable/resource/hole.gd b/demo/assets/scripts/environment/destructable/resource/hole.gd index 91fa969..2193255 100644 --- a/demo/assets/scripts/environment/destructable/resource/hole.gd +++ b/demo/assets/scripts/environment/destructable/resource/hole.gd @@ -3,11 +3,15 @@ extends Resource class_name Hole var hole_id: int -var vectors: PackedVector2Array +var vectors: PackedVector2Array # verticies +var area: float + func _init(hole_id: int, vectors: PackedVector2Array): self.hole_id = hole_id self.vectors = vectors + + self.area = UTIL.get_polygon_area(self.vectors) func center(): var avg_vert = Vector2.ZERO diff --git a/demo/assets/scripts/environment/destructable/util.gd b/demo/assets/scripts/environment/destructable/util.gd index f8119fd..be5432f 100644 --- a/demo/assets/scripts/environment/destructable/util.gd +++ b/demo/assets/scripts/environment/destructable/util.gd @@ -25,3 +25,13 @@ static func get_bounding_rect(vectors: PackedVector2Array) -> Rect2: # The 'position' of the Rect2 will be the minimum corner return rect + +static func get_polygon_area(vectors: PackedVector2Array) -> float: + var result := 0.0 + var num_vertices := vectors.size() + + for q in range(num_vertices): + var p = (q - 1 + num_vertices) % num_vertices + result += vectors[q].cross(vectors[p]) + + return abs(result * 0.5) diff --git a/demo/assets/scripts/test.gd b/demo/assets/scripts/test.gd deleted file mode 100644 index 6a9131f..0000000 --- a/demo/assets/scripts/test.gd +++ /dev/null @@ -1,24 +0,0 @@ -extends Node - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - var rtree = RectangleTree.new() - - var min1 = Vector2(0, 0) - var max1 = Vector2(1, 1) - var min2 = Vector2(0, 0) - var max2 = Vector2(0.5, 0.5) - - rtree.add(min1, max1, 0) - rtree.add(min2, max2, 1) - - var result = rtree.query(Vector2(0.25, 0.25)) - - print(result) - - rtree.remove(0) - - result = rtree.query(Vector2(0.25, 0.25)) - - print(result) diff --git a/demo/assets/scripts/test.gd.uid b/demo/assets/scripts/test.gd.uid deleted file mode 100644 index f610b8b..0000000 --- a/demo/assets/scripts/test.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://18smkusl55no diff --git a/demo/bin/libgtriangulation.linux.template_debug.x86_64.so b/demo/bin/libgtriangulation.linux.template_debug.x86_64.so index 24135a0..8f500a4 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/demo/levels/test.tscn b/demo/levels/test.tscn index 7ee68d4..fa985a2 100644 --- a/demo/levels/test.tscn +++ b/demo/levels/test.tscn @@ -183,6 +183,8 @@ verts2d = PackedVector2Array(-1, -1.5, 1, -1.5, 1, 1.5, -1, 1.5, -1, -1.5) meshInstance3d = NodePath("entity_2_mesh_instance") depth = -1.0 depth_position_offset = Vector3(0, 0, 0.5) +hole_proximity = 1.0 +edge_non_fracture = 0.01 [node name="entity_2_mesh_instance" type="MeshInstance3D" parent="FuncGodotMap/entity_2_func_destructablewall"] mesh = SubResource("ArrayMesh_eudka") @@ -192,9 +194,11 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.75, 2, -2.953125) script = ExtResource("6_u45fp") verts2d = PackedVector2Array(-2.546875, -1.5, 2.546875, -1.5, 2.546875, 1.5, -2.546875, 1.5, -2.546875, -1.5) meshInstance3d = NodePath("entity_3_mesh_instance") -extrusion_direction = 1 depth = -0.5 depth_position_offset = Vector3(-0.25, 0, 0) +extrusion_direction = 1 +hole_proximity = 1.0 +edge_non_fracture = 0.01 [node name="entity_3_mesh_instance" type="MeshInstance3D" parent="FuncGodotMap/entity_3_func_destructablewall"] mesh = SubResource("ArrayMesh_qtvpr") @@ -204,9 +208,11 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9.953125, 0.75, -4.5) script = ExtResource("6_u45fp") verts2d = PackedVector2Array(-1.546875, -2, 1.546875, -2, 1.546875, 2, -1.546875, 2, -1.546875, -2) meshInstance3d = NodePath("entity_4_mesh_instance") -extrusion_direction = 2 depth = -0.5 depth_position_offset = Vector3(0, -0.25, 0) +extrusion_direction = 2 +hole_proximity = 1.0 +edge_non_fracture = 0.01 [node name="entity_4_mesh_instance" type="MeshInstance3D" parent="FuncGodotMap/entity_4_func_destructablewall"] mesh = SubResource("ArrayMesh_drwxn") @@ -218,6 +224,8 @@ verts2d = PackedVector2Array(-1.046875, -1.5, 1.046875, -1.5, 1.046875, 1.5, -1. meshInstance3d = NodePath("entity_5_mesh_instance") depth = -1.0 depth_position_offset = Vector3(0, 0, 0.5) +hole_proximity = 1.0 +edge_non_fracture = 0.01 [node name="entity_5_mesh_instance" type="MeshInstance3D" parent="FuncGodotMap/entity_5_func_destructablewall"] mesh = SubResource("ArrayMesh_rmkky") @@ -227,9 +235,11 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.75, 2, 2.546875) script = ExtResource("6_u45fp") verts2d = PackedVector2Array(-2.546875, -1.5, 2.546875, -1.5, 2.546875, 1.5, -2.546875, 1.5, -2.546875, -1.5) meshInstance3d = NodePath("entity_6_mesh_instance") -extrusion_direction = 1 depth = -0.5 depth_position_offset = Vector3(-0.25, 0, 0) +extrusion_direction = 1 +hole_proximity = 1.0 +edge_non_fracture = 0.01 [node name="entity_6_mesh_instance" type="MeshInstance3D" parent="FuncGodotMap/entity_6_func_destructablewall"] mesh = SubResource("ArrayMesh_epu3l") @@ -239,9 +249,11 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 1, -3.7500305) script = ExtResource("6_u45fp") verts2d = PackedVector2Array(-1.0000001, -0.7500305, 0.9998779, -0.25006104, 1, -0.24996948, 1, 0.7500305, -1.0000001, 0.7500305, -1.0000001, -0.7500305) meshInstance3d = NodePath("entity_7_mesh_instance") -extrusion_direction = 2 depth = -1.0000000596046448 depth_position_offset = Vector3(0, -0.5, 0) +extrusion_direction = 2 +hole_proximity = 1.0 +edge_non_fracture = 0.01 [node name="entity_7_mesh_instance" type="MeshInstance3D" parent="FuncGodotMap/entity_7_func_destructablewall"] mesh = SubResource("ArrayMesh_lqn8c") @@ -253,6 +265,8 @@ verts2d = PackedVector2Array(-1.046875, -1.5, 1.046875, -1.5, 1.046875, 1.5, -1. meshInstance3d = NodePath("entity_8_mesh_instance") depth = -0.03125 depth_position_offset = Vector3(0, 0, 0.015625) +hole_proximity = 1.0 +edge_non_fracture = 0.01 [node name="entity_8_mesh_instance" type="MeshInstance3D" parent="FuncGodotMap/entity_8_func_destructablewall"] mesh = SubResource("ArrayMesh_08uri") diff --git a/demo/scenes/test.tscn b/demo/scenes/test.tscn deleted file mode 100644 index 3fbb327..0000000 --- a/demo/scenes/test.tscn +++ /dev/null @@ -1,6 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://bip0c3ydxx12r"] - -[ext_resource type="Script" uid="uid://18smkusl55no" path="res://assets/scripts/test.gd" id="1_errlg"] - -[node name="Test" type="Node"] -script = ExtResource("1_errlg") diff --git a/demo/trenchbroom/fgd/solid/func_destructable_wall.tres b/demo/trenchbroom/fgd/solid/func_destructable_wall.tres index c39cd9e..9559e92 100644 --- a/demo/trenchbroom/fgd/solid/func_destructable_wall.tres +++ b/demo/trenchbroom/fgd/solid/func_destructable_wall.tres @@ -10,7 +10,9 @@ classname = "func_destructablewall" description = "Set the brush entity as a destructable. " class_properties = { -"extrude_direction": 0 +"edge_non_fractured": 0.01, +"extrude_direction": 0, +"hole_proximity": 1.0 } node_class = "Node3D" metadata/_custom_type_script = "uid://5cow84q03m6a" diff --git a/src/rectangletree.cpp b/src/rectangletree.cpp index 9fc9277..ae9da64 100644 --- a/src/rectangletree.cpp +++ b/src/rectangletree.cpp @@ -16,6 +16,8 @@ void RectangleTree::_bind_methods() { &RectangleTree::query); ClassDB::bind_method(godot::D_METHOD("nearest", "point", "number"), &RectangleTree::nearest); + ClassDB::bind_method(godot::D_METHOD("query_rect", "min", "max"), + &RectangleTree::query_rect); } void RectangleTree::add(const Vector2 &min_bound, const Vector2 &max_bound, @@ -58,3 +60,18 @@ PackedInt32Array RectangleTree::nearest(const Vector2 &point, return return_value; } + +PackedInt32Array RectangleTree::query_rect(const Vector2 &min, + const Vector2 &max) { + Rect rect = Rect(min.x, min.y, max.x, max.y); + + PackedInt32Array return_value; + auto callbackLambda = [&return_value](int index) { + return_value.push_back(index); + return true; + }; + + tree.Search(rect.min, rect.max, callbackLambda); + + return return_value; +} diff --git a/src/rectangletree.hpp b/src/rectangletree.hpp index 13fd85a..d634098 100644 --- a/src/rectangletree.hpp +++ b/src/rectangletree.hpp @@ -51,4 +51,5 @@ public: void remove(const int &polygon_index); PackedInt32Array query(const Vector2 &point); PackedInt32Array nearest(const Vector2 &point, const int &number); + PackedInt32Array query_rect(const Vector2 &min, const Vector2 &max); }; diff --git a/src/rectangletree.os b/src/rectangletree.os index 04fa3e5..baec82f 100644 Binary files a/src/rectangletree.os and b/src/rectangletree.os differ