@driftengine/physics 3.61.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.
- package/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +503 -0
- package/dist/bodies.d.ts +121 -0
- package/dist/bodies.js +298 -0
- package/dist/buoyancy.d.ts +46 -0
- package/dist/buoyancy.js +45 -0
- package/dist/cloth.d.ts +226 -0
- package/dist/cloth.js +587 -0
- package/dist/collide/aabb.d.ts +10 -0
- package/dist/collide/aabb.js +11 -0
- package/dist/collide/body.d.ts +202 -0
- package/dist/collide/body.js +142 -0
- package/dist/collide/eject.d.ts +39 -0
- package/dist/collide/eject.js +142 -0
- package/dist/collide/index.d.ts +18 -0
- package/dist/collide/index.js +5 -0
- package/dist/collide/scratch.d.ts +8 -0
- package/dist/collide/scratch.js +9 -0
- package/dist/collide/segment.d.ts +12 -0
- package/dist/collide/segment.js +109 -0
- package/dist/collide/sweep.d.ts +3 -0
- package/dist/collide/sweep.js +1036 -0
- package/dist/colliderSet.d.ts +239 -0
- package/dist/colliderSet.js +546 -0
- package/dist/compoundContact.d.ts +70 -0
- package/dist/compoundContact.js +221 -0
- package/dist/controller.d.ts +351 -0
- package/dist/controller.js +641 -0
- package/dist/cylinder.d.ts +78 -0
- package/dist/cylinder.js +294 -0
- package/dist/cylinderContact.d.ts +7 -0
- package/dist/cylinderContact.js +704 -0
- package/dist/decompose.d.ts +105 -0
- package/dist/decompose.js +979 -0
- package/dist/events.d.ts +43 -0
- package/dist/events.js +95 -0
- package/dist/executor.d.ts +147 -0
- package/dist/executor.js +173 -0
- package/dist/faces.d.ts +26 -0
- package/dist/faces.js +34 -0
- package/dist/fingerprint.d.ts +61 -0
- package/dist/fingerprint.js +139 -0
- package/dist/groundMotor.d.ts +34 -0
- package/dist/groundMotor.js +41 -0
- package/dist/heightfieldShape.d.ts +128 -0
- package/dist/heightfieldShape.js +328 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +47 -0
- package/dist/island.d.ts +55 -0
- package/dist/island.js +227 -0
- package/dist/islandSolve.d.ts +70 -0
- package/dist/islandSolve.js +171 -0
- package/dist/islandWorker.d.ts +18 -0
- package/dist/islandWorker.js +125 -0
- package/dist/joints.d.ts +180 -0
- package/dist/joints.js +1094 -0
- package/dist/manifold.d.ts +89 -0
- package/dist/manifold.js +608 -0
- package/dist/mass.d.ts +53 -0
- package/dist/mass.js +353 -0
- package/dist/meshContact.d.ts +57 -0
- package/dist/meshContact.js +393 -0
- package/dist/meshShape.d.ts +76 -0
- package/dist/meshShape.js +175 -0
- package/dist/pairs.d.ts +62 -0
- package/dist/pairs.js +154 -0
- package/dist/query.d.ts +71 -0
- package/dist/query.js +683 -0
- package/dist/ragdoll.d.ts +135 -0
- package/dist/ragdoll.js +489 -0
- package/dist/shape.d.ts +177 -0
- package/dist/shape.js +533 -0
- package/dist/solver.d.ts +136 -0
- package/dist/solver.js +601 -0
- package/dist/stage.d.ts +167 -0
- package/dist/stage.js +350 -0
- package/dist/stallEscape.d.ts +141 -0
- package/dist/stallEscape.js +254 -0
- package/dist/sweptStep.d.ts +173 -0
- package/dist/sweptStep.js +472 -0
- package/dist/tree.d.ts +61 -0
- package/dist/tree.js +348 -0
- package/dist/vehicle.d.ts +154 -0
- package/dist/vehicle.js +343 -0
- package/dist/workerPool.d.ts +107 -0
- package/dist/workerPool.js +239 -0
- package/dist/workers.d.ts +37 -0
- package/dist/workers.js +35 -0
- package/dist/world.d.ts +298 -0
- package/dist/world.js +712 -0
- package/package.json +55 -0
- package/src/bodies.ts +369 -0
- package/src/buoyancy.ts +78 -0
- package/src/cloth.ts +734 -0
- package/src/collide/aabb.ts +28 -0
- package/src/collide/body.ts +336 -0
- package/src/collide/eject.ts +156 -0
- package/src/collide/index.ts +26 -0
- package/src/collide/scratch.ts +10 -0
- package/src/collide/segment.ts +127 -0
- package/src/collide/sweep.ts +1132 -0
- package/src/colliderSet.ts +637 -0
- package/src/compoundContact.ts +284 -0
- package/src/controller.ts +817 -0
- package/src/cylinder.ts +340 -0
- package/src/cylinderContact.ts +825 -0
- package/src/decompose.ts +1198 -0
- package/src/events.ts +108 -0
- package/src/executor.ts +224 -0
- package/src/faces.ts +37 -0
- package/src/fingerprint.ts +146 -0
- package/src/groundMotor.ts +53 -0
- package/src/heightfieldShape.ts +395 -0
- package/src/index.ts +164 -0
- package/src/island.ts +219 -0
- package/src/islandSolve.ts +218 -0
- package/src/islandWorker.ts +141 -0
- package/src/joints.ts +1367 -0
- package/src/manifold.ts +798 -0
- package/src/mass.ts +424 -0
- package/src/meshContact.ts +443 -0
- package/src/meshShape.ts +261 -0
- package/src/pairs.ts +169 -0
- package/src/query.ts +844 -0
- package/src/ragdoll.ts +662 -0
- package/src/shape.ts +656 -0
- package/src/solver.ts +873 -0
- package/src/stage.ts +406 -0
- package/src/stallEscape.ts +362 -0
- package/src/sweptStep.ts +609 -0
- package/src/tree.ts +366 -0
- package/src/vehicle.ts +489 -0
- package/src/workerPool.ts +283 -0
- package/src/workers.ts +38 -0
- package/src/world.ts +961 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import type { Aabb } from './collide/index.ts';
|
|
2
|
+
import type { ConvexShape } from './shape.ts';
|
|
3
|
+
/**
|
|
4
|
+
* One slot's packed bounds in bytes, for a reader walking `data` a slot at a time.
|
|
5
|
+
*
|
|
6
|
+
* **The stride is otherwise private and stays that way.** This exists because
|
|
7
|
+
* `fingerprintColliders` has to step slot by slot to skip the dead ones, and a literal 24 over
|
|
8
|
+
* there would be a second place for the packing to be wrong — which is the failure the `bounds`
|
|
9
|
+
* accessor already exists to prevent.
|
|
10
|
+
*/
|
|
11
|
+
export declare const STRIDE_BYTES: number;
|
|
12
|
+
/** A world obstacle: its bounds, and optionally the volume it really is. */
|
|
13
|
+
export interface Collider extends Aabb {
|
|
14
|
+
/** Points in world space — static shapes are baked, not transformed per query. */
|
|
15
|
+
shape?: ConvexShape | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Wrap a world-space shape in the bounds the broad phase needs. */
|
|
18
|
+
export declare function colliderFromShape(shape: ConvexShape): Collider;
|
|
19
|
+
/**
|
|
20
|
+
* The collider of a drawn box, exactly where it is drawn.
|
|
21
|
+
*
|
|
22
|
+
* Same centre and half-extents a mesh builder takes, so a game that draws a
|
|
23
|
+
* box gets its collision from the same numbers — nothing authored twice. The
|
|
24
|
+
* shape routes the touch through the shape sweep, which is what lets a lid sit
|
|
25
|
+
* flush with a walkable surface: the old world-axis path fought a body for the
|
|
26
|
+
* ground it stood on, and lids had to be sunk out of reach to compensate.
|
|
27
|
+
*/
|
|
28
|
+
export declare function boxCollider(cx: number, cy: number, cz: number, hx: number, hy: number, hz: number): Collider;
|
|
29
|
+
/**
|
|
30
|
+
* What a collider set costs, in bytes, split so a streaming budget can act on it.
|
|
31
|
+
*
|
|
32
|
+
* A single number would not answer the question a budget asks, which is what to drop.
|
|
33
|
+
*/
|
|
34
|
+
export interface ColliderBytes {
|
|
35
|
+
/**
|
|
36
|
+
* The packed bounds, the query stamps and the owners. Exact.
|
|
37
|
+
*
|
|
38
|
+
* **What was allocated, not what is used.** The arrays double as they grow and a free list
|
|
39
|
+
* recycles slots without ever shrinking them, so this is the memory actually held — which is
|
|
40
|
+
* what a budget needs and what `count` would misreport.
|
|
41
|
+
*/
|
|
42
|
+
readonly slots: number;
|
|
43
|
+
/** The distinct shape payloads reachable from live slots. Exact. */
|
|
44
|
+
readonly shapes: number;
|
|
45
|
+
/** The spatial hash: its buckets and their entries. Part measured, part estimated. */
|
|
46
|
+
readonly index: number;
|
|
47
|
+
/** The three above. */
|
|
48
|
+
readonly total: number;
|
|
49
|
+
}
|
|
50
|
+
export declare class ColliderSet {
|
|
51
|
+
static readonly MAX_HITS = 512;
|
|
52
|
+
/**
|
|
53
|
+
* The group the constructor's own colliders belong to, which `add` never mints and `remove`
|
|
54
|
+
* refuses.
|
|
55
|
+
*
|
|
56
|
+
* **Reserved because of the slots nothing inserts.** The constructor skips an `undefined` entry
|
|
57
|
+
* without putting it in any cell, and still counts it — so those slots are live and are in no
|
|
58
|
+
* bucket, and a removal that reached one would walk buckets it was never written to. Keeping the
|
|
59
|
+
* constructor's slots in a group nothing can drop puts that case out of reach instead of making
|
|
60
|
+
* it survivable.
|
|
61
|
+
*
|
|
62
|
+
* **A set meant to stream is constructed empty** and takes everything through `add`, which is
|
|
63
|
+
* what the refusal points at when it fires.
|
|
64
|
+
*/
|
|
65
|
+
static readonly BASE_GROUP: ColliderGroup;
|
|
66
|
+
/**
|
|
67
|
+
* The packed bounds, six floats a slot.
|
|
68
|
+
*
|
|
69
|
+
* **A reference to this is valid until the next `add`**, which may reallocate. `bounds()` is the
|
|
70
|
+
* reader that survives both that and a change of packing.
|
|
71
|
+
*
|
|
72
|
+
* **Its length is `capacity`, not `count`.** Those are equal on a set that has never had
|
|
73
|
+
* `remove` called on it, which is every set built the old way; after a removal the live slots
|
|
74
|
+
* are sparse and a walk of `0..count` reads the wrong ones. Walk `0..capacity` and skip
|
|
75
|
+
* `!liveAt(i)`.
|
|
76
|
+
*/
|
|
77
|
+
data: Float32Array;
|
|
78
|
+
private readonly cellSize;
|
|
79
|
+
private readonly cells;
|
|
80
|
+
private shapes;
|
|
81
|
+
/** Per-query stamp, so a box spanning several cells is reported once. */
|
|
82
|
+
private seen;
|
|
83
|
+
private stamp;
|
|
84
|
+
/** Slots allocated, live or not. */
|
|
85
|
+
private slots;
|
|
86
|
+
/** Slots in use. `count` reads this. */
|
|
87
|
+
private live;
|
|
88
|
+
/**
|
|
89
|
+
* Who holds each slot: `-1` for a free one, otherwise the group.
|
|
90
|
+
*
|
|
91
|
+
* One array for both liveness and provenance, which is what `bytes`, `liveAt` and the
|
|
92
|
+
* fingerprint each need, at four bytes a slot instead of a flag array beside a group array.
|
|
93
|
+
*/
|
|
94
|
+
private owner;
|
|
95
|
+
private readonly freeSlots;
|
|
96
|
+
/**
|
|
97
|
+
* Each group's slots, for the only operation that needs them.
|
|
98
|
+
*
|
|
99
|
+
* **A `Map`, and `remove` is its only reader.** `fingerprint.ts` states the rule this respects:
|
|
100
|
+
* nothing feeding a hash may iterate a `Map` or a `Set`, because insertion order would leak into
|
|
101
|
+
* the answer.
|
|
102
|
+
*/
|
|
103
|
+
private readonly groups;
|
|
104
|
+
private nextGroup;
|
|
105
|
+
constructor(boxes: readonly Collider[], cellSize?: number);
|
|
106
|
+
/** How many colliders the set holds. */
|
|
107
|
+
get count(): number;
|
|
108
|
+
/** How many slots are allocated, live or not. The true bound of a walk over `data`. */
|
|
109
|
+
get capacity(): number;
|
|
110
|
+
/** Whether slot `index` holds a collider. Every slot of a set that has never had `remove`
|
|
111
|
+
* called on it does. */
|
|
112
|
+
liveAt(index: number): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Take a batch of colliders and hand back the handle that drops them again.
|
|
115
|
+
*
|
|
116
|
+
* **The grid is updated for these colliders and for no others**, which is the whole point: a
|
|
117
|
+
* consumer whose world streams was rebuilding a set at every region crossing, at about 2.1 µs a
|
|
118
|
+
* box, and paying a whole frame for it.
|
|
119
|
+
*
|
|
120
|
+
* Slots come off the free list before the arrays grow, so a set that loads a ring of regions
|
|
121
|
+
* around a player settles at the ring's high-water mark instead of climbing with distance
|
|
122
|
+
* travelled. Live indices are untouched by this: a slot already in use stays where it is.
|
|
123
|
+
*/
|
|
124
|
+
add(boxes: readonly Collider[]): ColliderGroup;
|
|
125
|
+
/**
|
|
126
|
+
* Take everything in another set as one group, without hashing any of it again.
|
|
127
|
+
*
|
|
128
|
+
* **Copy and offset instead of recompute.** One `Float32Array.set` moves the packed bounds, the
|
|
129
|
+
* shapes are copied by reference, and each of the source's buckets is appended to this set's
|
|
130
|
+
* with a constant added to every index. Nothing is floored, no shape bounds are recomputed, and
|
|
131
|
+
* the result queries identically to a one-shot build of the union.
|
|
132
|
+
*
|
|
133
|
+
* **It appends past everything and skips the free list**, because a constant offset is what
|
|
134
|
+
* makes the bucket remap a copy: source slot `i` has to land at `base + i` and nothing may
|
|
135
|
+
* disturb that.
|
|
136
|
+
*
|
|
137
|
+
* **Which is exactly why the source's holes come across as holes.** A source that has had
|
|
138
|
+
* `remove` called on it — every streamed set — cannot be compacted on the way in, because
|
|
139
|
+
* skipping its holes would make the offset a function of position. Copying them while calling
|
|
140
|
+
* them live would be worse: those slots carry the bytes of colliders that were deleted, and a
|
|
141
|
+
* set reporting them would have resurrected geometry a consumer believed was gone. So liveness
|
|
142
|
+
* is copied with the bytes, the holes land on this set's free list, and the next `add` fills
|
|
143
|
+
* them. **Requiring a dense source instead** was the other option and was rejected: it would
|
|
144
|
+
* refuse the only input this was asked for.
|
|
145
|
+
*
|
|
146
|
+
* What a churned source does cost is its dead slots as bytes copied and space held until the
|
|
147
|
+
* free list drains them. Bounded, visible in `bytes()`, and not a leak.
|
|
148
|
+
*
|
|
149
|
+
* **A copy and not a move.** The source is unchanged and stays usable, which is what lets a
|
|
150
|
+
* caller keep a prototype region and stamp it more than once.
|
|
151
|
+
*
|
|
152
|
+
* `join(a, b, c)` is this in a loop, which is why there is no second method for it.
|
|
153
|
+
*/
|
|
154
|
+
absorb(other: ColliderSet): ColliderGroup;
|
|
155
|
+
/**
|
|
156
|
+
* Drop a group and everything in it.
|
|
157
|
+
*
|
|
158
|
+
* Refuses the base group and a group it does not hold; a streamer double-freeing a region is a
|
|
159
|
+
* bug, and a silent no-op hides it until the memory it was meant to release turns up in a
|
|
160
|
+
* budget.
|
|
161
|
+
*/
|
|
162
|
+
remove(group: ColliderGroup): void;
|
|
163
|
+
/** The volume collider `index` really is, or undefined where it is its box. */
|
|
164
|
+
shapeAt(index: number): ConvexShape | undefined;
|
|
165
|
+
/**
|
|
166
|
+
* The packed bounds of collider `index`, written into `out`. Allocation-free.
|
|
167
|
+
*
|
|
168
|
+
* `data` is public and the stride is not. A reader outside this file that decodes
|
|
169
|
+
* `data[i * 6 + 1]` by hand keeps working right up until the packing changes, and
|
|
170
|
+
* then reports confident nonsense rather than failing.
|
|
171
|
+
*/
|
|
172
|
+
bounds(index: number, out: Aabb): void;
|
|
173
|
+
query(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, out: Int32Array): number;
|
|
174
|
+
/**
|
|
175
|
+
* What this set costs in memory.
|
|
176
|
+
*
|
|
177
|
+
* **Because a consumer can count its own bytes and cannot see the engine's**, which makes a
|
|
178
|
+
* streaming budget half-measurable: the question "does the ring of regions around the player fit
|
|
179
|
+
* on a phone" has no answer without this.
|
|
180
|
+
*
|
|
181
|
+
* O(n) over slots and over the index, and it allocates a `Set` to count each distinct shape
|
|
182
|
+
* once. Not a per-frame call.
|
|
183
|
+
*/
|
|
184
|
+
bytes(): ColliderBytes;
|
|
185
|
+
/**
|
|
186
|
+
* How many bucket entries name a slot nothing holds. Always zero.
|
|
187
|
+
*
|
|
188
|
+
* **The one defect in this structure that has no symptom of its own**, which is why it gets a
|
|
189
|
+
* check of its own. A `remove` that misses a bucket entry leaves the slot marked dead — so the
|
|
190
|
+
* fingerprint skips it and is right, and nothing walks it by index — while the stale entry goes
|
|
191
|
+
* on naming it: `query` returns it, and the sweep reads its stale bounds and collides with
|
|
192
|
+
* geometry that is gone. No measurement of frame time, query cost or hash can see that.
|
|
193
|
+
*
|
|
194
|
+
* O(total entries) and not something to call in a frame. For tests and for the streaming check.
|
|
195
|
+
*/
|
|
196
|
+
auditCells(): number;
|
|
197
|
+
/**
|
|
198
|
+
* Unhook slots from every cell they occupy, then free them.
|
|
199
|
+
*
|
|
200
|
+
* **The same triple loop `insert` uses**, so the two cannot disagree about which cells a box
|
|
201
|
+
* occupies — which is the disagreement that would leave an entry behind. A bucket entry goes by
|
|
202
|
+
* swapping the last one into its place and popping, because bucket order carries no meaning, and
|
|
203
|
+
* an emptied bucket leaves `cells` so a dropped region costs a `Map.get` that misses instead of
|
|
204
|
+
* a scan.
|
|
205
|
+
*
|
|
206
|
+
* **Slots are freed in descending order** so the last-in-first-out pop hands them back
|
|
207
|
+
* ascending: a region added after another is dropped then lands on a contiguous run of that
|
|
208
|
+
* region's slots. Incidental locality and not a guarantee — see the compaction note in the
|
|
209
|
+
* design if a churned set's query cost ever drifts.
|
|
210
|
+
*/
|
|
211
|
+
private drop;
|
|
212
|
+
/**
|
|
213
|
+
* Room for `n` slots, growing by doubling.
|
|
214
|
+
*
|
|
215
|
+
* **The shape is `island.ts`'s `ensureBodies`, with one difference worth naming**: that one
|
|
216
|
+
* allocates and discards, because it rebuilds its arrays from scratch every tick, and these
|
|
217
|
+
* carry a world that has to survive the growth. So they copy.
|
|
218
|
+
*
|
|
219
|
+
* A grown `seen` is zero-filled by the allocation, which is the same thing `add` writes on a
|
|
220
|
+
* recycled slot and for the same reason.
|
|
221
|
+
*/
|
|
222
|
+
private ensureCapacity;
|
|
223
|
+
private insert;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* A handle to one batch of colliders, so a region can be dropped without naming its members.
|
|
227
|
+
*
|
|
228
|
+
* Opaque on purpose: it is an integer today and the only thing a caller may do with it is hand it
|
|
229
|
+
* back.
|
|
230
|
+
*/
|
|
231
|
+
export type ColliderGroup = number;
|
|
232
|
+
/**
|
|
233
|
+
* The stamp a query marks with next, or 0 meaning `seen` has to be cleared first.
|
|
234
|
+
*
|
|
235
|
+
* **Its own function because it cannot be reached by driving `query`.** The condition needs 2^31
|
|
236
|
+
* queries, which no test will do, so the decision is asserted where it is made rather than through
|
|
237
|
+
* the behaviour it protects.
|
|
238
|
+
*/
|
|
239
|
+
export declare function stampAfter(previous: number): number;
|