@perplexdotgg/bounce 1.0.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 (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/package.json +32 -0
  4. package/src/builders/ConvexHullBuilder.ts +437 -0
  5. package/src/builders/ConvexHullBuilder2d.ts +344 -0
  6. package/src/builders/ConvexHullBuilder3d.ts +1689 -0
  7. package/src/builders/HeightMapBuilder.ts +414 -0
  8. package/src/builders/TriangleMeshBuilder.ts +92 -0
  9. package/src/collision/CastShapesModule.ts +184 -0
  10. package/src/collision/CollideShapesModule.ts +152 -0
  11. package/src/collision/HeightMapCaster.ts +38 -0
  12. package/src/collision/HeightMapCollider.ts +33 -0
  13. package/src/collision/TriangleCaster.ts +249 -0
  14. package/src/collision/TriangleCollider.ts +308 -0
  15. package/src/collision/TriangleCollider2.ts +379 -0
  16. package/src/collision/activeEdge.ts +146 -0
  17. package/src/collision/cast/cast.ts +139 -0
  18. package/src/collision/cast/castCompoundVsCompound.ts +59 -0
  19. package/src/collision/cast/castCompoundVsConvex.ts +116 -0
  20. package/src/collision/cast/castConvexVsCompound.ts +123 -0
  21. package/src/collision/cast/castConvexVsConvex.ts +213 -0
  22. package/src/collision/cast/castConvexVsHeightMap.ts +73 -0
  23. package/src/collision/cast/castConvexVsTriangleMesh.ts +56 -0
  24. package/src/collision/cast/castRayVsCompound.ts +44 -0
  25. package/src/collision/cast/castRayVsConvex.ts +45 -0
  26. package/src/collision/cast/castRayVsHeightMap.ts +58 -0
  27. package/src/collision/cast/castRayVsTriangleMesh.ts +58 -0
  28. package/src/collision/closestPoints/closestPoints.ts +23 -0
  29. package/src/collision/closestPoints/computeBarycentricCoordinates2d.ts +32 -0
  30. package/src/collision/closestPoints/computeBarycentricCoordinates3d.ts +81 -0
  31. package/src/collision/closestPoints/computeClosestPointOnLine.ts +30 -0
  32. package/src/collision/closestPoints/computeClosestPointOnTetrahedron.ts +96 -0
  33. package/src/collision/closestPoints/computeClosestPointOnTriangle.ts +195 -0
  34. package/src/collision/closestPoints/isOriginOutsideOfPlane.ts +25 -0
  35. package/src/collision/closestPoints/isOriginOutsideOfTrianglePlanes.ts +72 -0
  36. package/src/collision/collide/collide.ts +146 -0
  37. package/src/collision/collide/collideCompoundVsCompound.ts +60 -0
  38. package/src/collision/collide/collideCompoundVsConvex.ts +59 -0
  39. package/src/collision/collide/collideCompoundVsHeightMap.ts +73 -0
  40. package/src/collision/collide/collideCompoundVsTriangleMesh.ts +56 -0
  41. package/src/collision/collide/collideConvexVsCompound.ts +57 -0
  42. package/src/collision/collide/collideConvexVsConvex.ts +225 -0
  43. package/src/collision/collide/collideConvexVsConvexImp.ts +236 -0
  44. package/src/collision/collide/collideConvexVsHeightMap.ts +53 -0
  45. package/src/collision/collide/collideConvexVsTriangleMesh.ts +58 -0
  46. package/src/collision/collide/collideHeightMapVsCompound.ts +69 -0
  47. package/src/collision/collide/collideHeightMapVsConvex.ts +53 -0
  48. package/src/collision/collide/collideSphereVsSphere.ts +81 -0
  49. package/src/collision/collide/collideTriangleMeshVsCompound.ts +58 -0
  50. package/src/collision/collide/collideTriangleMeshVsConvex.ts +58 -0
  51. package/src/collision/epa/EpaConvexHullBuilder.ts +397 -0
  52. package/src/collision/epa/StaticArray.ts +154 -0
  53. package/src/collision/epa/TriangleFactory.ts +32 -0
  54. package/src/collision/epa/arrays.ts +99 -0
  55. package/src/collision/epa/binaryHeap.ts +82 -0
  56. package/src/collision/epa/structs.ts +227 -0
  57. package/src/collision/gjk/GjkModule.ts +864 -0
  58. package/src/collision/gjk/PenetrationDepthModule.ts +493 -0
  59. package/src/collision/gjk/SupportPoints.ts +50 -0
  60. package/src/collision/imp/MinkowskiDifference.ts +36 -0
  61. package/src/collision/imp/computeExploredDistanceLowerUpperBound.ts +40 -0
  62. package/src/collision/imp/finalizeImpResult.ts +69 -0
  63. package/src/collision/imp/findContactImp.ts +196 -0
  64. package/src/collision/imp/imp.ts +28 -0
  65. package/src/collision/imp/incrementalMinimumDistanceExploreDirection.ts +207 -0
  66. package/src/collision/mpr/findPortal.ts +152 -0
  67. package/src/collision/mpr/mpr.ts +29 -0
  68. package/src/collision/mpr/updatePortal.ts +52 -0
  69. package/src/constraints/BaseConstraint.ts +50 -0
  70. package/src/constraints/ConstraintOptions.ts +22 -0
  71. package/src/constraints/ConstraintSolver.ts +119 -0
  72. package/src/constraints/DistanceConstraint.ts +229 -0
  73. package/src/constraints/FixedConstraint.ts +203 -0
  74. package/src/constraints/HingeConstraint.ts +460 -0
  75. package/src/constraints/PointConstraint.ts +108 -0
  76. package/src/constraints/components/AngleComponent.ts +226 -0
  77. package/src/constraints/components/AxisComponent.ts +263 -0
  78. package/src/constraints/components/HingeComponent.ts +215 -0
  79. package/src/constraints/components/Motor.ts +36 -0
  80. package/src/constraints/components/PointConstraintComponent.ts +179 -0
  81. package/src/constraints/components/RotationEulerComponent.ts +139 -0
  82. package/src/constraints/components/Spring.ts +30 -0
  83. package/src/constraints/components/SpringComponent.ts +71 -0
  84. package/src/constraints/types.ts +6 -0
  85. package/src/helpers.ts +147 -0
  86. package/src/index.ts +50 -0
  87. package/src/math/BasicTransform.ts +19 -0
  88. package/src/math/NumberValue.ts +13 -0
  89. package/src/math/isometry.ts +64 -0
  90. package/src/math/mat3.ts +529 -0
  91. package/src/math/mat4.ts +588 -0
  92. package/src/math/quat.ts +193 -0
  93. package/src/math/scalar.ts +81 -0
  94. package/src/math/tensor.ts +17 -0
  95. package/src/math/vec3.ts +589 -0
  96. package/src/math/vec4.ts +10 -0
  97. package/src/physics/Body.ts +581 -0
  98. package/src/physics/CollisionFilter.ts +52 -0
  99. package/src/physics/SleepModule.ts +163 -0
  100. package/src/physics/broadphase/BodyPairsModule.ts +363 -0
  101. package/src/physics/broadphase/BvhModule.ts +237 -0
  102. package/src/physics/broadphase/BvhTree.ts +803 -0
  103. package/src/physics/broadphase/ConstraintPairsModule.ts +385 -0
  104. package/src/physics/broadphase/TriangleMeshBvhTree.ts +379 -0
  105. package/src/physics/manifold/ContactManifold.ts +227 -0
  106. package/src/physics/manifold/ContactManifoldModule.ts +623 -0
  107. package/src/physics/manifold/Face.ts +119 -0
  108. package/src/physics/manifold/ManifoldCache.ts +116 -0
  109. package/src/physics/manifold/clipping/clipPolyVsEdge.ts +131 -0
  110. package/src/physics/manifold/clipping/clipPolyVsPlane.ts +73 -0
  111. package/src/physics/manifold/clipping/clipPolyVsPoly.ts +72 -0
  112. package/src/physics/narrowphase/CollideBodiesModule.ts +755 -0
  113. package/src/physics/solver/ContactConstraintModule.ts +659 -0
  114. package/src/physics/solver/ManifoldConstraint.ts +420 -0
  115. package/src/physics/solver/estimateCollisionResponse.ts +146 -0
  116. package/src/shape/Aabb.ts +400 -0
  117. package/src/shape/Box.ts +231 -0
  118. package/src/shape/Capsule.ts +332 -0
  119. package/src/shape/CompoundShape.ts +288 -0
  120. package/src/shape/Convex.ts +130 -0
  121. package/src/shape/ConvexHull.ts +423 -0
  122. package/src/shape/Cylinder.ts +313 -0
  123. package/src/shape/HeightMap.ts +511 -0
  124. package/src/shape/Line.ts +14 -0
  125. package/src/shape/Plane.ts +116 -0
  126. package/src/shape/Ray.ts +81 -0
  127. package/src/shape/Segment.ts +25 -0
  128. package/src/shape/Shape.ts +77 -0
  129. package/src/shape/Sphere.ts +181 -0
  130. package/src/shape/TransformedShape.ts +51 -0
  131. package/src/shape/Triangle.ts +122 -0
  132. package/src/shape/TriangleMesh.ts +186 -0
  133. package/src/types.ts +1 -0
  134. package/src/world.ts +1335 -0
  135. package/tests/BodyPairsModule.test.ts +71 -0
  136. package/tests/BvhTree.test.ts +406 -0
  137. package/tests/test.md +642 -0
  138. package/tests/vec3.test.ts +12 -0
  139. package/tsconfig.json +20 -0
  140. package/vite.config.js +40 -0
@@ -0,0 +1,385 @@
1
+ import {
2
+ createClass,
3
+ LazyReferenceType,
4
+ NumberType,
5
+ PoolClass,
6
+ PropertyDefinition,
7
+ PropertyDefinitionMap,
8
+ PropertyDefinitionReference,
9
+ ReferenceType,
10
+ } from "monomorph";
11
+ import { Body, BodyType } from "../Body";
12
+ import { type ConstraintInterface, baseConstraintProps, ConstraintType } from "../../constraints/BaseConstraint";
13
+ import { PointConstraint } from "../../constraints/PointConstraint";
14
+ import { FixedConstraint } from "../../constraints/FixedConstraint";
15
+ import { DistanceConstraint } from "../../constraints/DistanceConstraint";
16
+ import { HingeConstraint } from "../../constraints/HingeConstraint";
17
+ import { Constraint } from "../../constraints/types";
18
+
19
+ baseConstraintProps;
20
+
21
+ const constraintPairNodeProps = {
22
+ bodyA: LazyReferenceType((() => Body) as () => never) as PropertyDefinitionReference<Body | null, true>,
23
+ bodyB: LazyReferenceType((() => Body) as () => never) as PropertyDefinitionReference<Body | null, true>,
24
+ edgeA: LazyReferenceType((() => ConstraintPairEdge) as () => never) as PropertyDefinitionReference<
25
+ ConstraintPairEdge | null,
26
+ true
27
+ >,
28
+ edgeB: LazyReferenceType((() => ConstraintPairEdge) as () => never) as PropertyDefinitionReference<
29
+ ConstraintPairEdge | null,
30
+ true
31
+ >,
32
+ constraintType: NumberType(ConstraintType.pointConstraint) as PropertyDefinition<ConstraintType, true>,
33
+ constraintPoint: LazyReferenceType((() => PointConstraint) as () => never) as PropertyDefinitionReference<PointConstraint | null, true>,
34
+ constraintFixed: LazyReferenceType((() => FixedConstraint) as () => never) as PropertyDefinitionReference<FixedConstraint | null, true>,
35
+ constraintDistance: LazyReferenceType((() => DistanceConstraint) as () => never) as PropertyDefinitionReference<DistanceConstraint | null, true>,
36
+ constraintHinge: LazyReferenceType((() => HingeConstraint) as () => never) as PropertyDefinitionReference<HingeConstraint | null, true>,
37
+ } as const satisfies PropertyDefinitionMap;
38
+
39
+ const afterConstructorCode = `
40
+ this.world = null;
41
+ this.constraints = [null, null, null, null];
42
+ `;
43
+
44
+ export class ConstraintPairNode extends createClass<ConstraintPairNode, typeof constraintPairNodeProps>(
45
+ constraintPairNodeProps,
46
+ { afterConstructorCode }
47
+ ) {
48
+ declare constraints: [Constraint | null, Constraint | null, Constraint | null, Constraint | null];
49
+
50
+ containsStaticBody() {
51
+ return this.bodyA!.type === BodyType.static || this.bodyB!.type === BodyType.static;
52
+ }
53
+
54
+ get constraint(): Constraint | null {
55
+ return this.constraints[this.constraintType];
56
+ }
57
+
58
+ set constraint(value: Constraint | null) {
59
+ if (value === null) {
60
+ this.constraints[this.constraintType] = null;
61
+ return;
62
+ }
63
+ this.constraints[this.constraintType] = null;
64
+ this.constraints[value.type] = value;
65
+ this.constraintType = value.type;
66
+ }
67
+ }
68
+
69
+ const constraintPairEdgeProps = {
70
+ node: LazyReferenceType((() => ConstraintPairNode) as () => never) as PropertyDefinitionReference<
71
+ ConstraintPairNode | null,
72
+ true
73
+ >,
74
+ next: LazyReferenceType((() => ConstraintPairEdge) as () => never) as PropertyDefinitionReference<
75
+ ConstraintPairEdge | null,
76
+ true
77
+ >,
78
+ prev: LazyReferenceType((() => ConstraintPairEdge) as () => never) as PropertyDefinitionReference<
79
+ ConstraintPairEdge | null,
80
+ true
81
+ >,
82
+ } as const satisfies PropertyDefinitionMap;
83
+
84
+ export class ConstraintPairEdge extends createClass<ConstraintPairEdge, typeof constraintPairEdgeProps>(
85
+ constraintPairEdgeProps
86
+ ) {}
87
+
88
+ export class ConstraintPairsModule {
89
+ nodes: PoolClass<ConstraintPairNode>;
90
+ edges: PoolClass<ConstraintPairEdge>;
91
+
92
+ walkStack: ConstraintPairNode[];
93
+ walkVisited: Set<ConstraintPairNode>;
94
+
95
+ bodiesToSleep: Set<Body>;
96
+ _sleepTimeThreshold: number;
97
+ _allReady: boolean;
98
+
99
+ constructor(constraintPairNodePool: PoolClass<ConstraintPairNode>, constraintPairEdgePool: PoolClass<ConstraintPairEdge>) {
100
+ this.nodes = constraintPairNodePool;
101
+ this.edges = constraintPairEdgePool;
102
+
103
+ this.walkStack = [];
104
+ this.walkVisited = new Set();
105
+
106
+ this.bodiesToSleep = new Set();
107
+ this._sleepTimeThreshold = 0.5;
108
+ this._allReady = true;
109
+ }
110
+
111
+ _checkReadyToSleep = (neighbor: ConstraintPairNode) => {
112
+ this.walkVisited.add(neighbor);
113
+ const bodyA = neighbor.bodyA!;
114
+ const bodyB = neighbor.bodyB!;
115
+
116
+ if (bodyA.type === BodyType.dynamic) {
117
+ this.bodiesToSleep.add(bodyA);
118
+ if (!bodyA.isReadyToSleep(this._sleepTimeThreshold)) {
119
+ this._allReady = false;
120
+ return true;
121
+ }
122
+ }
123
+
124
+ if (bodyB.type === BodyType.dynamic) {
125
+ this.bodiesToSleep.add(bodyB);
126
+ if (!bodyB.isReadyToSleep(this._sleepTimeThreshold)) {
127
+ this._allReady = false;
128
+ return true;
129
+ }
130
+ }
131
+
132
+ if (
133
+ !neighbor.bodyA!.isReadyToSleep(this._sleepTimeThreshold) ||
134
+ !neighbor.bodyB!.isReadyToSleep(this._sleepTimeThreshold)
135
+ ) {
136
+ this._allReady = false;
137
+ return true;
138
+ }
139
+ return false;
140
+ };
141
+
142
+ /**
143
+ * creates a body pair. O(1)
144
+ * @param bodyA
145
+ * @param bodyB
146
+ * @returns
147
+ */
148
+ createPair(constraint: ConstraintInterface) {
149
+ const bodyA = constraint.bodyA!;
150
+ const bodyB = constraint.bodyB!;
151
+
152
+ // // if like-type, ensure bodyA has the lower index
153
+ // if (bodyA.type === bodyB.type && bodyA.index > bodyB.index) {
154
+ // const temp = bodyA;
155
+ // bodyA = bodyB;
156
+ // bodyB = temp;
157
+ // }
158
+ // // if unlike-type, ensure bodyA is the dynamic
159
+ // if (bodyA.type !== bodyB.type && bodyA.type !== BodyType.dynamic) {
160
+ // const temp = bodyA;
161
+ // bodyA = bodyB;
162
+ // bodyB = temp;
163
+ // }
164
+
165
+ // allocations
166
+ const node = ConstraintPairNode.create(undefined, this.nodes);
167
+ node.bodyA = null;
168
+ node.bodyB = null;
169
+ node.edgeA = null;
170
+ node.edgeB = null;
171
+
172
+ const edgeA = ConstraintPairEdge.create(undefined, this.edges);
173
+ edgeA.next = null;
174
+ edgeA.prev = null;
175
+ edgeA.node = null;
176
+
177
+ const edgeB = ConstraintPairEdge.create(undefined, this.edges);
178
+ edgeB.next = null;
179
+ edgeB.prev = null;
180
+ edgeB.node = null;
181
+
182
+ // wire up node
183
+ node.bodyA = bodyA;
184
+ node.bodyB = bodyB;
185
+ node.edgeA = edgeA;
186
+ node.edgeB = edgeB;
187
+
188
+ // wire up edgeA
189
+ edgeA.node = node;
190
+ edgeA.prev = null;
191
+ edgeA.next = bodyA.firstPotentialConstraintPairEdge;
192
+ if (bodyA.firstPotentialConstraintPairEdge) {
193
+ bodyA.firstPotentialConstraintPairEdge.prev = edgeA;
194
+ }
195
+ bodyA.firstPotentialConstraintPairEdge = edgeA;
196
+
197
+ // wire up edgeB
198
+ edgeB.node = node;
199
+ edgeB.prev = null;
200
+ edgeB.next = bodyB.firstPotentialConstraintPairEdge;
201
+ if (bodyB.firstPotentialConstraintPairEdge) {
202
+ bodyB.firstPotentialConstraintPairEdge.prev = edgeB;
203
+ }
204
+ bodyB.firstPotentialConstraintPairEdge = edgeB;
205
+
206
+ constraint.constraintPairNode = node;
207
+ node.constraint = constraint as Constraint;
208
+
209
+ return node;
210
+ }
211
+
212
+ /**
213
+ * destroys a body pair. O(k) where k is the number of pairs involving bodyA
214
+ */
215
+ destroyPair(constraint: ConstraintInterface) {
216
+ const bodyA = constraint.bodyA!;
217
+ const bodyB = constraint.bodyB!;
218
+
219
+ let edge = bodyA.firstPotentialConstraintPairEdge;
220
+
221
+ // walk through the edges of bodyA
222
+ while (edge) {
223
+ // find the node
224
+ const node = edge.node!;
225
+ if (node.bodyB !== bodyB) {
226
+ edge = edge.next;
227
+ continue;
228
+ }
229
+
230
+ // unlink edgeA from bodyA
231
+ const edgeA = node.edgeA!;
232
+ if (edgeA.prev) {
233
+ edgeA.prev.next = edgeA.next;
234
+ } else {
235
+ bodyA.firstPotentialConstraintPairEdge = edgeA.next;
236
+ }
237
+ if (edgeA.next) {
238
+ edgeA.next.prev = edgeA.prev;
239
+ }
240
+
241
+ // unlink edgeB from bodyB
242
+ const edgeB = node.edgeB!;
243
+ if (edgeB.prev) {
244
+ edgeB.prev.next = edgeB.next;
245
+ } else {
246
+ bodyB.firstPotentialConstraintPairEdge = edgeB.next;
247
+ }
248
+ if (edgeB.next) {
249
+ edgeB.next.prev = edgeB.prev;
250
+ }
251
+
252
+ constraint.constraintPairNode = null;
253
+ node.constraint = null;
254
+
255
+ // destroy the objects
256
+ edgeA.destroy();
257
+ edgeB.destroy();
258
+ node.destroy();
259
+
260
+ return true;
261
+ }
262
+
263
+ return false;
264
+ }
265
+
266
+ /**
267
+ * destroys all pairs of involving a single body. O(k) where k is the number of pairs involving body
268
+ */
269
+ destroyAllPairsOfOne(body: Body) {
270
+ let destroyed = false;
271
+
272
+ // walk through the edges of body
273
+ let edge = body.firstPotentialConstraintPairEdge;
274
+ while (edge) {
275
+ const nextEdge = edge.next as ConstraintPairEdge | null;
276
+
277
+ const node = edge.node!;
278
+ const edgeA = node.edgeA!;
279
+ const edgeB = node.edgeB!;
280
+
281
+ const otherBody = node.bodyA === body ? node.bodyB! : node.bodyA!;
282
+ const otherEdge = node.bodyA === body ? edgeB : edgeA;
283
+
284
+ // unlink the other edge from the other body
285
+ if (otherEdge.prev) {
286
+ otherEdge.prev.next = otherEdge.next;
287
+ } else {
288
+ otherBody.firstPotentialConstraintPairEdge = otherEdge.next;
289
+ }
290
+ if (otherEdge.next) {
291
+ otherEdge.next.prev = otherEdge.prev;
292
+ }
293
+
294
+ node.constraint!.constraintPairNode = null;
295
+ node.constraint!.destroy();
296
+ node.constraint = null;
297
+
298
+ // destroy the objects
299
+ edgeA.destroy();
300
+ edgeB.destroy();
301
+ node.destroy();
302
+
303
+ edge = nextEdge;
304
+ destroyed = true;
305
+ }
306
+
307
+ body.firstPotentialConstraintPairEdge = null;
308
+
309
+ return destroyed;
310
+ }
311
+
312
+ *iteratePairsOfOne(body: Body): IterableIterator<ConstraintPairNode> {
313
+ let edge = body.firstPotentialConstraintPairEdge;
314
+ while (edge) {
315
+ yield edge.node!;
316
+ edge = edge.next;
317
+ }
318
+ }
319
+
320
+ *iteratePairs(): IterableIterator<ConstraintPairNode> {
321
+ for (const node of this.nodes) {
322
+ yield node;
323
+ }
324
+ }
325
+
326
+ walk(startNode: ConstraintPairNode, onNode: (node: ConstraintPairNode) => boolean) {
327
+ const visited = this.walkVisited;
328
+ visited.clear();
329
+
330
+ const stack = this.walkStack;
331
+ stack.length = 0;
332
+ stack.push(startNode);
333
+
334
+ while (stack.length > 0) {
335
+ const node = stack.pop()!;
336
+ if (visited.has(node)) {
337
+ continue;
338
+ }
339
+ visited.add(node);
340
+
341
+ if (onNode(node)) {
342
+ return;
343
+ }
344
+
345
+ const bodyA = node.bodyA!;
346
+ const bodyB = node.bodyB!;
347
+
348
+ for (const neighbor of this.iteratePairsOfOne(bodyA)) {
349
+ if (!visited.has(neighbor)) {
350
+ stack.push(neighbor);
351
+ }
352
+ }
353
+
354
+ for (const neighbor of this.iteratePairsOfOne(bodyB)) {
355
+ if (!visited.has(neighbor)) {
356
+ stack.push(neighbor);
357
+ }
358
+ }
359
+ }
360
+ }
361
+
362
+ sleepAllReadyBodies(sleepTimeThreshold: number) {
363
+ this.walkVisited.clear();
364
+ this.bodiesToSleep.clear();
365
+ this._sleepTimeThreshold = sleepTimeThreshold;
366
+ this._allReady = true;
367
+
368
+ for (const node of this.nodes) {
369
+ if (this.walkVisited.has(node)) {
370
+ continue;
371
+ }
372
+
373
+ this.bodiesToSleep.clear();
374
+ this._allReady = true;
375
+
376
+ this.walk(node, this._checkReadyToSleep);
377
+
378
+ if (this._allReady) {
379
+ for (const body of this.bodiesToSleep) {
380
+ body.sleep();
381
+ }
382
+ }
383
+ }
384
+ }
385
+ }