babylon-box3d 0.2.0 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babylon-box3d",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Box3D physics for Babylon.js: Erin Catto's 3D rigid body engine compiled to WebAssembly plus a physics v2 plugin (Box3DPlugin)",
5
5
  "license": "MIT",
6
6
  "author": "Andrew Butt",
@@ -29,10 +29,18 @@
29
29
  "types": "./lib/esm/box3d.d.ts",
30
30
  "default": "./lib/esm/box3d.js"
31
31
  },
32
+ "./wasm/threads": {
33
+ "types": "./lib/esm-threads/box3d.d.ts",
34
+ "default": "./lib/esm-threads/box3d.js"
35
+ },
32
36
  "./wasm/node": {
33
37
  "types": "./lib/node/box3d.d.ts",
34
38
  "default": "./lib/node/box3d.mjs"
35
39
  },
40
+ "./wasm/node-threads": {
41
+ "types": "./lib/node-threads/box3d.d.ts",
42
+ "default": "./lib/node-threads/box3d.mjs"
43
+ },
36
44
  "./lib/*": "./lib/*",
37
45
  "./umd/*": "./umd/*",
38
46
  "./package.json": "./package.json"
@@ -1,4 +1,4 @@
1
- /* babylon-box3d 0.2.0 | MIT | https://github.com/Pryme8/babylon-box3d */
1
+ /* babylon-box3d 0.4.0 | MIT | https://github.com/Pryme8/babylon-box3d */
2
2
  "use strict";
3
3
  var BABYLONBOX3D = (() => {
4
4
  var __create = Object.create;
@@ -7,6 +7,9 @@ var BABYLONBOX3D = (() => {
7
7
  var __getOwnPropNames = Object.getOwnPropertyNames;
8
8
  var __getProtoOf = Object.getPrototypeOf;
9
9
  var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __esm = (fn, res) => function __init() {
11
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ };
10
13
  var __commonJS = (cb, mod) => function __require() {
11
14
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
12
15
  };
@@ -122,13 +125,43 @@ var BABYLONBOX3D = (() => {
122
125
  }
123
126
  });
124
127
 
128
+ // box3d-global:babylon-box3d/wasm
129
+ var wasm_exports = {};
130
+ __export(wasm_exports, {
131
+ default: () => wasm_default
132
+ });
133
+ var wasm_default;
134
+ var init_wasm = __esm({
135
+ "box3d-global:babylon-box3d/wasm"() {
136
+ if (typeof Box3D === "undefined") {
137
+ throw new Error("babylon.box3d.js needs lib/umd/box3d.umd.js loaded first");
138
+ }
139
+ wasm_default = Box3D;
140
+ }
141
+ });
142
+
143
+ // box3d-threads-stub:babylon-box3d/wasm/threads
144
+ var threads_exports = {};
145
+ __export(threads_exports, {
146
+ default: () => threads_default
147
+ });
148
+ function threads_default() {
149
+ throw new Error('babylon.box3d.js is the script tag build and has no threaded module. Install the package and import it, or use LoadBox3D({ threads: "auto" }).');
150
+ }
151
+ var init_threads = __esm({
152
+ "box3d-threads-stub:babylon-box3d/wasm/threads"() {
153
+ }
154
+ });
155
+
125
156
  // src/index.ts
126
157
  var index_exports = {};
127
158
  __export(index_exports, {
128
159
  BOX3D_HEIGHT_FIELD_HOLE: () => BOX3D_HEIGHT_FIELD_HOLE,
129
160
  Box3D: () => wasm_default,
130
161
  Box3DPlugin: () => Box3DPlugin,
131
- Box3DWheelJoint: () => Box3DWheelJoint
162
+ Box3DWheelJoint: () => Box3DWheelJoint,
163
+ CanUseBox3DThreads: () => CanUseBox3DThreads,
164
+ LoadBox3D: () => LoadBox3D
132
165
  });
133
166
 
134
167
  // src/box3dPlugin.ts
@@ -412,6 +445,7 @@ var BABYLONBOX3D = (() => {
412
445
  "_bx_DestroyBody",
413
446
  "_bx_DestroyJoint",
414
447
  "_bx_DestroyWorld",
448
+ "_bx_GetMaxWorkers",
415
449
  "_bx_GetRejectedSlotCount",
416
450
  "_bx_Joint_EnableLimit",
417
451
  "_bx_Joint_EnableMotor",
@@ -467,6 +501,7 @@ var BABYLONBOX3D = (() => {
467
501
  "_bx_World_GetMoveEvents",
468
502
  "_bx_World_GetSensorEvents",
469
503
  "_bx_World_GetStats",
504
+ "_bx_World_GetWorkerCount",
470
505
  "_bx_World_SetGravity",
471
506
  "_bx_World_SetMaximumLinearSpeed",
472
507
  "_bx_World_Step"
@@ -476,13 +511,16 @@ var BABYLONBOX3D = (() => {
476
511
  * Creates a Box3D plugin.
477
512
  * @param _useDeltaForWorldStep step the world with the frame delta (true) or a fixed time step (false)
478
513
  * @param box3dModule the resolved Box3D WASM module (await Box3DModule())
514
+ * @param options worker count and sub steps, see IBox3DPluginOptions
479
515
  */
480
- constructor(_useDeltaForWorldStep = true, box3dModule) {
516
+ constructor(_useDeltaForWorldStep = true, box3dModule, options) {
481
517
  this._useDeltaForWorldStep = _useDeltaForWorldStep;
482
518
  /** Name of the plugin */
483
519
  this.name = "Box3DPlugin";
484
520
  /** Number of solver sub steps per world step. Box3D recommends 4. */
485
521
  this.subStepCount = 4;
522
+ /** Workers box3d puts on a world step, counting the calling thread. 1 unless the threaded module asked for more. */
523
+ this.workerCount = 1;
486
524
  /** Wall clock time of the last world step in milliseconds (JavaScript side, includes the event sync). */
487
525
  this.lastStepTimeMs = 0;
488
526
  this._worldSlot = 0;
@@ -518,10 +556,40 @@ var BABYLONBOX3D = (() => {
518
556
  }
519
557
  this._b3 = box3dModule;
520
558
  this.world = box3dModule;
521
- this._worldSlot = this._b3._bx_CreateWorld(0, -9.81, 0);
559
+ if (options?.subStepCount !== void 0) {
560
+ this.subStepCount = Math.max(1, Math.round(options.subStepCount));
561
+ }
562
+ this._worldSlot = this._b3._bx_CreateWorld(0, -9.81, 0, this._resolveWorkerCount(options?.workerCount));
522
563
  if (!this._worldSlot) {
523
564
  throw new Error("Box3D: could not create a world (max worlds reached?)");
524
565
  }
566
+ this.workerCount = Math.max(1, this._b3._bx_World_GetWorkerCount(this._worldSlot));
567
+ }
568
+ /**
569
+ * Turns the requested worker count into one this module can honour. Only the threaded build reports more than one,
570
+ * and asking a single threaded build for workers is quiet enough to look like it worked, so say so once.
571
+ * @param requested the constructor option
572
+ * @returns the count to create the world with
573
+ */
574
+ _resolveWorkerCount(requested) {
575
+ const supported = Math.max(1, this._b3._bx_GetMaxWorkers());
576
+ if (requested === void 0) {
577
+ return 1;
578
+ }
579
+ let wanted;
580
+ if (requested === "auto") {
581
+ const cores = typeof navigator !== "undefined" && navigator.hardwareConcurrency || 4;
582
+ wanted = Math.max(1, Math.floor(cores / 2));
583
+ } else {
584
+ wanted = Math.max(1, Math.round(requested));
585
+ }
586
+ if (wanted > 1 && supported === 1) {
587
+ this._warnOnce(
588
+ "single-threaded-module",
589
+ `${wanted} workers were requested, but this Box3D module was built without threads, so the step stays on the calling thread. Load the threaded build (LoadBox3D({ threads: true }), or babylon-box3d/wasm/threads) from a cross origin isolated page: it needs SharedArrayBuffer, which browsers only allow with the COOP and COEP headers set.`
590
+ );
591
+ }
592
+ return Math.min(wanted, supported);
525
593
  }
526
594
  // ----------------------------------------------------------------------------------------
527
595
  // helpers
@@ -1344,7 +1412,6 @@ var BABYLONBOX3D = (() => {
1344
1412
  const b = options.pointB ?? import_math_vector.Vector3.UpReadOnly;
1345
1413
  const axis = b.subtract(a);
1346
1414
  const height = axis.length();
1347
- const mid = a.add(b).scaleInPlace(0.5);
1348
1415
  const q = this._tmpQuat[0];
1349
1416
  if (height > 1e-6) {
1350
1417
  axis.scaleInPlace(1 / height);
@@ -1352,11 +1419,15 @@ var BABYLONBOX3D = (() => {
1352
1419
  } else {
1353
1420
  q.set(0, 0, 0, 1);
1354
1421
  }
1355
- this._registerShape(shape, b3._bx_ShapeDesc_CreateCylinder(height, options.radius ?? 0, 16, mid.x, mid.y, mid.z, q.x, q.y, q.z, q.w), type);
1422
+ this._registerShape(shape, b3._bx_ShapeDesc_CreateCylinder(height, options.radius ?? 0, 16, a.x, a.y, a.z, q.x, q.y, q.z, q.w), type);
1356
1423
  break;
1357
1424
  }
1358
1425
  case import_IPhysicsEnginePlugin.PhysicsShapeType.CONVEX_HULL:
1359
1426
  case import_IPhysicsEnginePlugin.PhysicsShapeType.MESH: {
1427
+ if (!options.mesh && options.positions) {
1428
+ this._initShapeFromPositions(shape, type, options.positions, options.positionIndices);
1429
+ break;
1430
+ }
1360
1431
  const mesh = options.mesh;
1361
1432
  if (!mesh) {
1362
1433
  throw new Error("No mesh provided to create physics shape.");
@@ -1438,6 +1509,37 @@ var BABYLONBOX3D = (() => {
1438
1509
  throw new Error("Unsupported Shape Type.");
1439
1510
  }
1440
1511
  }
1512
+ _initShapeFromPositions(shape, type, positions, indices) {
1513
+ const b3 = this._b3;
1514
+ if (positions.length % 3 !== 0) {
1515
+ throw new Error(`positions needs x, y, z triplets, got ${positions.length} numbers`);
1516
+ }
1517
+ const vertexCount = positions.length / 3;
1518
+ if (type === import_IPhysicsEnginePlugin.PhysicsShapeType.CONVEX_HULL) {
1519
+ this._registerShape(
1520
+ shape,
1521
+ this._withFloatBuffer(positions, (ptr) => b3._bx_ShapeDesc_CreateHull(ptr, vertexCount)),
1522
+ type
1523
+ );
1524
+ return;
1525
+ }
1526
+ if (!indices || indices.length % 3 !== 0) {
1527
+ throw new Error("a MESH shape from positions needs positionIndices, three per triangle");
1528
+ }
1529
+ for (let i = 0; i < indices.length; i++) {
1530
+ if (indices[i] < 0 || indices[i] >= vertexCount || !Number.isInteger(indices[i])) {
1531
+ throw new Error(`positionIndices[${i}] is ${indices[i]}, but there are ${vertexCount} points`);
1532
+ }
1533
+ }
1534
+ this._registerShape(
1535
+ shape,
1536
+ this._withFloatBuffer(
1537
+ positions,
1538
+ (vptr) => this._withIntBuffer(indices, (iptr) => b3._bx_ShapeDesc_CreateMesh(vptr, vertexCount, iptr, indices.length / 3, 1, 1, 1, 0, 0))
1539
+ ),
1540
+ type
1541
+ );
1542
+ }
1441
1543
  // Re-instantiates the shape on every body that uses it (or uses a container holding it). Only needed for geometry
1442
1544
  // and child changes; filters, materials and density are applied in place, see _syncShapeUsers.
1443
1545
  _refreshShapeUsers(data, visited = /* @__PURE__ */ new Set()) {
@@ -2592,11 +2694,32 @@ var BABYLONBOX3D = (() => {
2592
2694
  }
2593
2695
  };
2594
2696
 
2595
- // box3d-global:babylon-box3d/wasm
2596
- if (typeof Box3D === "undefined") {
2597
- throw new Error("babylon.box3d.js needs lib/umd/box3d.umd.js loaded first");
2697
+ // src/index.ts
2698
+ init_wasm();
2699
+
2700
+ // src/loadBox3D.ts
2701
+ function CanUseBox3DThreads() {
2702
+ if (typeof SharedArrayBuffer === "undefined") {
2703
+ return false;
2704
+ }
2705
+ const isolated = globalThis.crossOriginIsolated;
2706
+ return isolated === void 0 || isolated;
2707
+ }
2708
+ async function LoadBox3D(options = {}) {
2709
+ const { threads = false, ...moduleOptions } = options;
2710
+ const wantsThreads = threads === "auto" ? CanUseBox3DThreads() : threads;
2711
+ if (wantsThreads) {
2712
+ if (threads === true && !CanUseBox3DThreads()) {
2713
+ throw new Error(
2714
+ 'babylon-box3d: the threaded build needs SharedArrayBuffer, which this page does not have. Serve it with the Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers, or use LoadBox3D({ threads: "auto" }) to fall back to the single threaded build.'
2715
+ );
2716
+ }
2717
+ const threaded = await Promise.resolve().then(() => (init_threads(), threads_exports));
2718
+ return threaded.default(moduleOptions);
2719
+ }
2720
+ const plain = await Promise.resolve().then(() => (init_wasm(), wasm_exports));
2721
+ return plain.default(moduleOptions);
2598
2722
  }
2599
- var wasm_default = Box3D;
2600
2723
  return __toCommonJS(index_exports);
2601
2724
  })();
2602
2725
  //# sourceMappingURL=babylon.box3d.js.map