@woosh/meep-engine 2.147.0 → 2.149.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_bridge_islands.d.ts +23 -0
  3. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_bridge_islands.d.ts.map +1 -0
  4. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_bridge_islands.js +295 -0
  5. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.d.ts +4 -4
  6. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.d.ts.map +1 -1
  7. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.js +48 -52
  8. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.d.ts +23 -21
  9. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.d.ts.map +1 -1
  10. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.js +41 -406
  11. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts +5 -4
  12. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -1
  13. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +400 -395
  14. package/src/engine/navigation/mesh/NavigationMesh.d.ts +6 -2
  15. package/src/engine/navigation/mesh/NavigationMesh.d.ts.map +1 -1
  16. package/src/engine/navigation/mesh/NavigationMesh.js +234 -212
  17. package/src/engine/navigation/mesh/bt_mesh_face_find_path.d.ts +7 -3
  18. package/src/engine/navigation/mesh/bt_mesh_face_find_path.d.ts.map +1 -1
  19. package/src/engine/navigation/mesh/bt_mesh_face_find_path.js +67 -73
  20. package/src/engine/navigation/mesh/build/enforce_agent_height_clearance.d.ts +16 -5
  21. package/src/engine/navigation/mesh/build/enforce_agent_height_clearance.d.ts.map +1 -1
  22. package/src/engine/navigation/mesh/build/enforce_agent_height_clearance.js +262 -147
  23. package/src/engine/navigation/mesh/build/navmesh_build_topology.d.ts.map +1 -1
  24. package/src/engine/navigation/mesh/build/navmesh_build_topology.js +33 -3
  25. package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts +4 -1
  26. package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts.map +1 -1
  27. package/src/engine/navigation/mesh/bvh_query_nearest_face.js +164 -131
  28. package/src/engine/physics/body/SolverBodyState.d.ts +142 -0
  29. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -0
  30. package/src/engine/physics/body/SolverBodyState.js +251 -0
  31. package/src/engine/physics/broadphase/generate_pairs.d.ts +2 -1
  32. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
  33. package/src/engine/physics/broadphase/generate_pairs.js +110 -108
  34. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  35. package/src/engine/physics/constraint/solve_constraints.js +691 -673
  36. package/src/engine/physics/ecs/PhysicsSystem.d.ts +21 -18
  37. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  38. package/src/engine/physics/ecs/PhysicsSystem.js +223 -91
  39. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +23 -0
  40. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
  41. package/src/engine/physics/inertia/world_inverse_inertia.js +116 -77
  42. package/src/engine/physics/integration/integrate_position.d.ts +11 -1
  43. package/src/engine/physics/integration/integrate_position.d.ts.map +1 -1
  44. package/src/engine/physics/integration/integrate_position.js +97 -79
  45. package/src/engine/physics/integration/integrate_velocity.d.ts +12 -3
  46. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  47. package/src/engine/physics/integration/integrate_velocity.js +201 -160
  48. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
  49. package/src/engine/physics/narrowphase/box_box_manifold.js +750 -665
  50. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -1
  51. package/src/engine/physics/narrowphase/box_triangle_contact.js +4 -34
  52. package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts +16 -0
  53. package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts.map +1 -0
  54. package/src/engine/physics/narrowphase/clip_against_axis_uv.js +49 -0
  55. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  56. package/src/engine/physics/narrowphase/narrowphase_step.js +24 -3
  57. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  58. package/src/engine/physics/queries/raycast.js +201 -198
  59. package/src/engine/physics/solver/solve_contacts.d.ts +2 -2
  60. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  61. package/src/engine/physics/solver/solve_contacts.js +1341 -1173
@@ -10,13 +10,17 @@ export class NavigationMesh {
10
10
  * @param {BinaryTopology} source
11
11
  * @param {number} [agent_radius]
12
12
  * @param {number} [agent_height]
13
+ * @param {number} [agent_max_step_height] agent can bridge vertical gaps in topology, such as stepping up a stair
14
+ * @param {number} [agent_max_step_distance] agent can bridge lateral gaps in topology, such as stepping over a hole in the floor
13
15
  * @param {number} [agent_max_climb_angle] In radians, how steep of an angle can the agent go up by
14
16
  * @param {Vector3} [up] Defines world's "UP" direction, this is what the agent will respect for climbing constraint
15
17
  */
16
- build({ source, agent_radius, agent_height, agent_max_climb_angle, up, }: BinaryTopology): void;
18
+ build({ source, agent_radius, agent_height, agent_max_step_height, agent_max_step_distance, agent_max_climb_angle, up, }: BinaryTopology): void;
17
19
  /**
18
20
  * Compute a walkable path between the two points.
19
- * The result is a sequence of 3d points written into `output`. First point matches start, last point matches goal (snapped onto the mesh).
21
+ * The result is a sequence of 3d points written into `output`. The first and last points are the
22
+ * start and goal snapped onto the mesh surface (the closest walkable point to each query position),
23
+ * so they may differ from the raw `start_*`/`goal_*` inputs when those lie off the mesh.
20
24
  *
21
25
  * @param {Float32Array} output packed XYZ triples
22
26
  * @param {number} start_x
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationMesh.d.ts","sourceRoot":"","sources":["../../../../../src/engine/navigation/mesh/NavigationMesh.js"],"names":[],"mappings":"AAgCA;IAEI,yBAAgC;IAEhC;;;OAGG;IACH,KAFU,GAAG,CAEG;IAEhB;;;;;;;OAOG;IACH,0EANW,cAAc,QAwBxB;IAGD;;;;;;;;;;;;OAYG;IACH,kBATW,YAAY,WACZ,MAAM,WACN,MAAM,WACN,MAAM,UACN,MAAM,UACN,MAAM,UACN,MAAM,GACJ,MAAM,CA+HlB;CAEJ;+BAlN4C,gEAAgE;oBADzF,gCAAgC"}
1
+ {"version":3,"file":"NavigationMesh.d.ts","sourceRoot":"","sources":["../../../../../src/engine/navigation/mesh/NavigationMesh.js"],"names":[],"mappings":"AAoCA;IAEI,yBAAgC;IAEhC;;;OAGG;IACH,KAFU,GAAG,CAEG;IAEhB;;;;;;;;;OASG;IACH,0HARW,cAAc,QA8BxB;IAGD;;;;;;;;;;;;;;OAcG;IACH,kBATW,YAAY,WACZ,MAAM,WACN,MAAM,WACN,MAAM,UACN,MAAM,UACN,MAAM,UACN,MAAM,GACJ,MAAM,CAyIlB;CAEJ;+BAxO4C,gEAAgE;oBADzF,gCAAgC"}
@@ -1,212 +1,234 @@
1
- import { BVH } from "../../../core/bvh2/bvh3/BVH.js";
2
- import { BinaryTopology, NULL_POINTER } from "../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
3
- import { bt_faces_shared_loop } from "../../../core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js";
4
- import Vector3 from "../../../core/geom/Vector3.js";
5
- import { bt_mesh_face_find_path } from "./bt_mesh_face_find_path.js";
6
- import { navmesh_build_topology } from "./build/navmesh_build_topology.js";
7
- import { bvh_build_from_bt_mesh } from "./bvh_build_from_bt_mesh.js";
8
- import { bvh_query_nearest_face } from "./bvh_query_nearest_face.js";
9
- import { funnel_string_pull } from "./funnel_string_pull.js";
10
-
11
- /**
12
- * Hard cap on the number of faces we traverse in a single path query.
13
- * Limits scratch buffer sizes; paths longer than this are truncated by the A* search.
14
- * @type {number}
15
- */
16
- const MAX_FACE_PATH_LENGTH = 1024;
17
-
18
- // face path IDs or (later) final path vertex indices
19
- const scratch_array_u32 = new Uint32Array(MAX_FACE_PATH_LENGTH);
20
-
21
- // one more portal than face-path length (start portal + one between each consecutive pair of faces + goal portal)
22
- const MAX_PORTAL_COUNT = MAX_FACE_PATH_LENGTH + 1;
23
-
24
- // [left0, right0, left1, right1, ...]
25
- const scratch_portal_vertices = new Uint32Array(MAX_PORTAL_COUNT * 2);
26
-
27
- // flat XYZ triples, one per portal
28
- const scratch_portal_normals = new Float32Array(MAX_PORTAL_COUNT * 3);
29
-
30
- // flat XYZ triples; indices 0 and 1 are start/goal, then 2 vertices per intermediate portal
31
- const scratch_vertices = new Float32Array((2 + (MAX_PORTAL_COUNT - 2) * 2) * 3);
32
-
33
- export class NavigationMesh {
34
-
35
- topology = new BinaryTopology();
36
-
37
- /**
38
- * Used for raycasts and neighborhood search.
39
- * @type {BVH}
40
- */
41
- bvh = new BVH();
42
-
43
- /**
44
- * Build from given scene geometry
45
- * @param {BinaryTopology} source
46
- * @param {number} [agent_radius]
47
- * @param {number} [agent_height]
48
- * @param {number} [agent_max_climb_angle] In radians, how steep of an angle can the agent go up by
49
- * @param {Vector3} [up] Defines world's "UP" direction, this is what the agent will respect for climbing constraint
50
- */
51
- build({
52
- source,
53
- agent_radius = 0,
54
- agent_height = 0,
55
- agent_max_climb_angle = Math.PI / 4,
56
- up = Vector3.up,
57
- }) {
58
-
59
- navmesh_build_topology({
60
- destination: this.topology,
61
- source,
62
- agent_radius,
63
- agent_height,
64
- agent_max_climb_angle,
65
- up,
66
- });
67
-
68
- bvh_build_from_bt_mesh(this.bvh, this.topology);
69
- }
70
-
71
-
72
- /**
73
- * Compute a walkable path between the two points.
74
- * The result is a sequence of 3d points written into `output`. First point matches start, last point matches goal (snapped onto the mesh).
75
- *
76
- * @param {Float32Array} output packed XYZ triples
77
- * @param {number} start_x
78
- * @param {number} start_y
79
- * @param {number} start_z
80
- * @param {number} goal_x
81
- * @param {number} goal_y
82
- * @param {number} goal_z
83
- * @returns {number} number of 3d points written to `output` (0 if no path was found)
84
- */
85
- find_path(
86
- output,
87
- start_x, start_y, start_z,
88
- goal_x, goal_y, goal_z
89
- ) {
90
-
91
- const mesh = this.topology;
92
- const bvh = this.bvh;
93
-
94
- const start_face_id = bvh_query_nearest_face(bvh, mesh, start_x, start_y, start_z);
95
-
96
- if (start_face_id === NULL_POINTER) {
97
- // probably topology is empty
98
- return 0;
99
- }
100
-
101
- const goal_face_id = bvh_query_nearest_face(bvh, mesh, goal_x, goal_y, goal_z);
102
-
103
- if (goal_face_id === NULL_POINTER) {
104
- // should never happen if we got the start face
105
- return 0;
106
- }
107
-
108
- if (goal_face_id === start_face_id) {
109
- // path within the same triangle
110
-
111
- output[0] = start_x;
112
- output[1] = start_y;
113
- output[2] = start_z;
114
-
115
- output[3] = goal_x;
116
- output[4] = goal_y;
117
- output[5] = goal_z;
118
-
119
- return 2;
120
- }
121
-
122
- const face_path_length = bt_mesh_face_find_path(scratch_array_u32, start_face_id, goal_face_id, mesh);
123
-
124
- if (face_path_length === 0) {
125
- // no face path exists (disconnected topology)
126
- return 0;
127
- }
128
-
129
- // build portals
130
- // ==================
131
-
132
- // initialize vertex data pool, vertex index 0 = start, vertex index 1 = goal
133
- scratch_vertices[0] = start_x;
134
- scratch_vertices[1] = start_y;
135
- scratch_vertices[2] = start_z;
136
-
137
- scratch_vertices[3] = goal_x;
138
- scratch_vertices[4] = goal_y;
139
- scratch_vertices[5] = goal_z;
140
-
141
- let next_vertex_index = 2;
142
-
143
- // start portal, degenerate portal at the start point, exiting the start face
144
- scratch_portal_vertices[0] = 0;
145
- scratch_portal_vertices[1] = 0;
146
-
147
- mesh.face_read_normal(scratch_portal_normals, 0, start_face_id);
148
-
149
- let portal_index = 1;
150
-
151
- // intermediate portals sit on the shared edge between two consecutive faces along the path;
152
- // the edge is read in the winding order of the face we are exiting, giving a directed (left, right) pair
153
- for (let i = 1; i < face_path_length; i++) {
154
-
155
- const face_from = scratch_array_u32[i - 1];
156
- const face_to = scratch_array_u32[i];
157
-
158
- const loop = bt_faces_shared_loop(mesh, face_from, face_to);
159
-
160
- const left_vertex = mesh.loop_read_vertex(loop);
161
- const right_vertex = mesh.loop_read_vertex(mesh.loop_read_next(loop));
162
-
163
- const left_index = next_vertex_index++;
164
- const right_index = next_vertex_index++;
165
-
166
- mesh.vertex_read_coordinate(scratch_vertices, left_index * 3, left_vertex);
167
- mesh.vertex_read_coordinate(scratch_vertices, right_index * 3, right_vertex);
168
-
169
- const portal_address = portal_index * 2;
170
- scratch_portal_vertices[portal_address] = left_index;
171
- scratch_portal_vertices[portal_address + 1] = right_index;
172
-
173
- mesh.face_read_normal(scratch_portal_normals, portal_index * 3, face_from);
174
-
175
- portal_index++;
176
- }
177
-
178
- // goal portal, degenerate at the goal point, uses the normal of the face containing the goal
179
- const goal_portal_address = portal_index * 2;
180
-
181
- scratch_portal_vertices[goal_portal_address] = 1;
182
- scratch_portal_vertices[goal_portal_address + 1] = 1;
183
-
184
- mesh.face_read_normal(scratch_portal_normals, portal_index * 3, goal_face_id);
185
-
186
- portal_index++;
187
-
188
- // execute string pulling
189
- const path_vertex_count = funnel_string_pull(
190
- scratch_array_u32,
191
- 0,
192
- scratch_portal_vertices,
193
- scratch_portal_normals,
194
- portal_index,
195
- scratch_vertices,
196
- );
197
-
198
- // build the final path
199
- for (let i = 0; i < path_vertex_count; i++) {
200
- const vertex_index = scratch_array_u32[i];
201
-
202
- output[i * 3] = scratch_vertices[vertex_index * 3];
203
- output[i * 3 + 1] = scratch_vertices[vertex_index * 3 + 1];
204
- output[i * 3 + 2] = scratch_vertices[vertex_index * 3 + 2];
205
-
206
- }
207
-
208
- return path_vertex_count;
209
-
210
- }
211
-
212
- }
1
+ import { BVH } from "../../../core/bvh2/bvh3/BVH.js";
2
+ import { BinaryTopology, NULL_POINTER } from "../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
3
+ import { bt_faces_shared_loop } from "../../../core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js";
4
+ import Vector3 from "../../../core/geom/Vector3.js";
5
+ import { bt_mesh_face_find_path } from "./bt_mesh_face_find_path.js";
6
+ import { navmesh_build_topology } from "./build/navmesh_build_topology.js";
7
+ import { bvh_build_from_bt_mesh } from "./bvh_build_from_bt_mesh.js";
8
+ import { bvh_query_nearest_face } from "./bvh_query_nearest_face.js";
9
+ import { funnel_string_pull } from "./funnel_string_pull.js";
10
+
11
+ /**
12
+ * Hard cap on the number of faces we traverse in a single path query.
13
+ * Limits scratch buffer sizes; paths longer than this are truncated by the A* search.
14
+ * @type {number}
15
+ */
16
+ const MAX_FACE_PATH_LENGTH = 1024;
17
+
18
+ // face path IDs or (later) final path vertex indices
19
+ const scratch_array_u32 = new Uint32Array(MAX_FACE_PATH_LENGTH);
20
+
21
+ // one more portal than face-path length (start portal + one between each consecutive pair of faces + goal portal)
22
+ const MAX_PORTAL_COUNT = MAX_FACE_PATH_LENGTH + 1;
23
+
24
+ // [left0, right0, left1, right1, ...]
25
+ const scratch_portal_vertices = new Uint32Array(MAX_PORTAL_COUNT * 2);
26
+
27
+ // flat XYZ triples, one per portal
28
+ const scratch_portal_normals = new Float32Array(MAX_PORTAL_COUNT * 3);
29
+
30
+ // flat XYZ triples; indices 0 and 1 are start/goal, then 2 vertices per intermediate portal
31
+ const scratch_vertices = new Float32Array((2 + (MAX_PORTAL_COUNT - 2) * 2) * 3);
32
+
33
+ // snapped (on-mesh) start/goal positions, reused across queries
34
+ const scratch_start_point = new Float32Array(3);
35
+ const scratch_goal_point = new Float32Array(3);
36
+
37
+ export class NavigationMesh {
38
+
39
+ topology = new BinaryTopology();
40
+
41
+ /**
42
+ * Used for raycasts and neighborhood search.
43
+ * @type {BVH}
44
+ */
45
+ bvh = new BVH();
46
+
47
+ /**
48
+ * Build from given scene geometry
49
+ * @param {BinaryTopology} source
50
+ * @param {number} [agent_radius]
51
+ * @param {number} [agent_height]
52
+ * @param {number} [agent_max_step_height] agent can bridge vertical gaps in topology, such as stepping up a stair
53
+ * @param {number} [agent_max_step_distance] agent can bridge lateral gaps in topology, such as stepping over a hole in the floor
54
+ * @param {number} [agent_max_climb_angle] In radians, how steep of an angle can the agent go up by
55
+ * @param {Vector3} [up] Defines world's "UP" direction, this is what the agent will respect for climbing constraint
56
+ */
57
+ build({
58
+ source,
59
+ agent_radius = 0,
60
+ agent_height = 0,
61
+ agent_max_step_height = 0,
62
+ agent_max_step_distance = 0,
63
+ agent_max_climb_angle = Math.PI / 4,
64
+ up = Vector3.up,
65
+ }) {
66
+
67
+ navmesh_build_topology({
68
+ destination: this.topology,
69
+ source,
70
+ agent_radius,
71
+ agent_height,
72
+ agent_max_step_height,
73
+ agent_max_step_distance,
74
+ agent_max_climb_angle,
75
+ up,
76
+ });
77
+
78
+ bvh_build_from_bt_mesh(this.bvh, this.topology);
79
+ }
80
+
81
+
82
+ /**
83
+ * Compute a walkable path between the two points.
84
+ * The result is a sequence of 3d points written into `output`. The first and last points are the
85
+ * start and goal snapped onto the mesh surface (the closest walkable point to each query position),
86
+ * so they may differ from the raw `start_*`/`goal_*` inputs when those lie off the mesh.
87
+ *
88
+ * @param {Float32Array} output packed XYZ triples
89
+ * @param {number} start_x
90
+ * @param {number} start_y
91
+ * @param {number} start_z
92
+ * @param {number} goal_x
93
+ * @param {number} goal_y
94
+ * @param {number} goal_z
95
+ * @returns {number} number of 3d points written to `output` (0 if no path was found)
96
+ */
97
+ find_path(
98
+ output,
99
+ start_x, start_y, start_z,
100
+ goal_x, goal_y, goal_z
101
+ ) {
102
+
103
+ const mesh = this.topology;
104
+ const bvh = this.bvh;
105
+
106
+ const start_face_id = bvh_query_nearest_face(bvh, mesh, start_x, start_y, start_z, scratch_start_point);
107
+
108
+ if (start_face_id === NULL_POINTER) {
109
+ // probably topology is empty
110
+ return 0;
111
+ }
112
+
113
+ const goal_face_id = bvh_query_nearest_face(bvh, mesh, goal_x, goal_y, goal_z, scratch_goal_point);
114
+
115
+ if (goal_face_id === NULL_POINTER) {
116
+ // should never happen if we got the start face
117
+ return 0;
118
+ }
119
+
120
+ // snap the query points onto the mesh surface; the path begins/ends on the walkable surface,
121
+ // not at the (possibly off-mesh) raw query coordinates
122
+ const snapped_start_x = scratch_start_point[0];
123
+ const snapped_start_y = scratch_start_point[1];
124
+ const snapped_start_z = scratch_start_point[2];
125
+
126
+ const snapped_goal_x = scratch_goal_point[0];
127
+ const snapped_goal_y = scratch_goal_point[1];
128
+ const snapped_goal_z = scratch_goal_point[2];
129
+
130
+ if (goal_face_id === start_face_id) {
131
+ // path within the same triangle
132
+
133
+ output[0] = snapped_start_x;
134
+ output[1] = snapped_start_y;
135
+ output[2] = snapped_start_z;
136
+
137
+ output[3] = snapped_goal_x;
138
+ output[4] = snapped_goal_y;
139
+ output[5] = snapped_goal_z;
140
+
141
+ return 2;
142
+ }
143
+
144
+ const face_path_length = bt_mesh_face_find_path(scratch_array_u32, start_face_id, goal_face_id, mesh, MAX_FACE_PATH_LENGTH);
145
+
146
+ if (face_path_length === 0) {
147
+ // no face path exists (disconnected topology)
148
+ return 0;
149
+ }
150
+
151
+ // build portals
152
+ // ==================
153
+
154
+ // initialize vertex data pool, vertex index 0 = start, vertex index 1 = goal (snapped on-mesh)
155
+ scratch_vertices[0] = snapped_start_x;
156
+ scratch_vertices[1] = snapped_start_y;
157
+ scratch_vertices[2] = snapped_start_z;
158
+
159
+ scratch_vertices[3] = snapped_goal_x;
160
+ scratch_vertices[4] = snapped_goal_y;
161
+ scratch_vertices[5] = snapped_goal_z;
162
+
163
+ let next_vertex_index = 2;
164
+
165
+ // start portal, degenerate portal at the start point, exiting the start face
166
+ scratch_portal_vertices[0] = 0;
167
+ scratch_portal_vertices[1] = 0;
168
+
169
+ mesh.face_read_normal(scratch_portal_normals, 0, start_face_id);
170
+
171
+ let portal_index = 1;
172
+
173
+ // intermediate portals sit on the shared edge between two consecutive faces along the path;
174
+ // the edge is read in the winding order of the face we are exiting, giving a directed (left, right) pair
175
+ for (let i = 1; i < face_path_length; i++) {
176
+
177
+ const face_from = scratch_array_u32[i - 1];
178
+ const face_to = scratch_array_u32[i];
179
+
180
+ const loop = bt_faces_shared_loop(mesh, face_from, face_to);
181
+
182
+ const left_vertex = mesh.loop_read_vertex(loop);
183
+ const right_vertex = mesh.loop_read_vertex(mesh.loop_read_next(loop));
184
+
185
+ const left_index = next_vertex_index++;
186
+ const right_index = next_vertex_index++;
187
+
188
+ mesh.vertex_read_coordinate(scratch_vertices, left_index * 3, left_vertex);
189
+ mesh.vertex_read_coordinate(scratch_vertices, right_index * 3, right_vertex);
190
+
191
+ const portal_address = portal_index * 2;
192
+ scratch_portal_vertices[portal_address] = left_index;
193
+ scratch_portal_vertices[portal_address + 1] = right_index;
194
+
195
+ mesh.face_read_normal(scratch_portal_normals, portal_index * 3, face_from);
196
+
197
+ portal_index++;
198
+ }
199
+
200
+ // goal portal, degenerate at the goal point, uses the normal of the face containing the goal
201
+ const goal_portal_address = portal_index * 2;
202
+
203
+ scratch_portal_vertices[goal_portal_address] = 1;
204
+ scratch_portal_vertices[goal_portal_address + 1] = 1;
205
+
206
+ mesh.face_read_normal(scratch_portal_normals, portal_index * 3, goal_face_id);
207
+
208
+ portal_index++;
209
+
210
+ // execute string pulling
211
+ const path_vertex_count = funnel_string_pull(
212
+ scratch_array_u32,
213
+ 0,
214
+ scratch_portal_vertices,
215
+ scratch_portal_normals,
216
+ portal_index,
217
+ scratch_vertices,
218
+ );
219
+
220
+ // build the final path
221
+ for (let i = 0; i < path_vertex_count; i++) {
222
+ const vertex_index = scratch_array_u32[i];
223
+
224
+ output[i * 3] = scratch_vertices[vertex_index * 3];
225
+ output[i * 3 + 1] = scratch_vertices[vertex_index * 3 + 1];
226
+ output[i * 3 + 2] = scratch_vertices[vertex_index * 3 + 2];
227
+
228
+ }
229
+
230
+ return path_vertex_count;
231
+
232
+ }
233
+
234
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Find a path through topology faces.
2
+ * Find a shortest path through topology faces.
3
3
  * If a path is found - the result will contain start and goal faces.
4
4
  *
5
5
  * NOTE: if either start or goal faces are not part of the topology - an empty path will be produced.
@@ -8,7 +8,11 @@
8
8
  * @param {number} start_face_id
9
9
  * @param {number} goal_face_id
10
10
  * @param {BinaryTopology} topology
11
- * @returns {number} number of faces that make up the path. This will be 0 if no path is found.
11
+ * @param {number} [max_path_length=Infinity] cap on the number of faces written to `output`. If the
12
+ * shortest corridor is longer than this it does not fit the buffer and 0 is returned. Pass the
13
+ * capacity of `output` to guarantee no out-of-bounds writes.
14
+ * @returns {number} number of faces that make up the path. This will be 0 if no path is found (or the
15
+ * path does not fit `max_path_length`).
12
16
  */
13
- export function bt_mesh_face_find_path(output: number[] | Uint32Array, start_face_id: number, goal_face_id: number, topology: BinaryTopology): number;
17
+ export function bt_mesh_face_find_path(output: number[] | Uint32Array, start_face_id: number, goal_face_id: number, topology: BinaryTopology, max_path_length?: number): number;
14
18
  //# sourceMappingURL=bt_mesh_face_find_path.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bt_mesh_face_find_path.d.ts","sourceRoot":"","sources":["../../../../../src/engine/navigation/mesh/bt_mesh_face_find_path.js"],"names":[],"mappings":"AAsHA;;;;;;;;;;;GAWG;AACH,+CANW,MAAM,EAAE,GAAC,WAAW,iBACpB,MAAM,gBACN,MAAM,6BAEJ,MAAM,CAoFlB"}
1
+ {"version":3,"file":"bt_mesh_face_find_path.d.ts","sourceRoot":"","sources":["../../../../../src/engine/navigation/mesh/bt_mesh_face_find_path.js"],"names":[],"mappings":"AA2GA;;;;;;;;;;;;;;;GAeG;AACH,+CAVW,MAAM,EAAE,GAAC,WAAW,iBACpB,MAAM,gBACN,MAAM,8CAEN,MAAM,GAGJ,MAAM,CAsFlB"}