@woosh/meep-engine 2.94.2 → 2.94.4

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.
@@ -502,6 +502,19 @@ assert.isFunction = function (value, name = 'value') {
502
502
  }
503
503
  };
504
504
 
505
+ /**
506
+ *
507
+ * @param {Object|*} value
508
+ * @param {string} [name]
509
+ */
510
+ assert.isObject = function (value, name = 'value') {
511
+ const typeofValue = typeof value;
512
+
513
+ if (typeofValue !== 'object') {
514
+ throw new Error(`expected ${name} to be an object, instead was '${typeofValue}'(=${value})`);
515
+ }
516
+ };
517
+
505
518
  /**
506
519
  *
507
520
  * @param {number|*} value
@@ -1723,6 +1736,23 @@ function clamp$1(value, min, max) {
1723
1736
  }
1724
1737
  }
1725
1738
 
1739
+ /**
1740
+ * Clamps a value to 0..1 range
1741
+ * Same as `clamp(value, 0, 1)`
1742
+ * Works the same as `saturate` function in GLSL
1743
+ * @param {number} value
1744
+ * @returns {number}
1745
+ */
1746
+ function clamp01(value) {
1747
+ if (value < 0) {
1748
+ return 0;
1749
+ } else if (value > 1) {
1750
+ return 1;
1751
+ } else {
1752
+ return value;
1753
+ }
1754
+ }
1755
+
1726
1756
  /**
1727
1757
  * Very small value, used for comparison when compensation for rounding error is required
1728
1758
  * @type {number}
@@ -1752,16 +1782,6 @@ function lerp$1(a, b, fraction) {
1752
1782
  return (b - a) * fraction + a;
1753
1783
  }
1754
1784
 
1755
- /**
1756
- * Returns lowest value out of 2 supplied
1757
- * @param {number} a
1758
- * @param {number} b
1759
- * @returns {number}
1760
- */
1761
- function min2(a, b) {
1762
- return a < b ? a : b;
1763
- }
1764
-
1765
1785
  /**
1766
1786
  *
1767
1787
  * @param {number} v
@@ -4252,23 +4272,23 @@ let Quaternion$1 = class Quaternion {
4252
4272
  this.set(x, y, z, w);
4253
4273
  }
4254
4274
 
4255
-
4256
4275
  /**
4257
- * @see https://github.com/toji/gl-matrix/blob/master/src/gl-matrix/quat.js
4258
- * @param {Quaternion} other
4276
+ *
4277
+ * @param {Quaternion} from
4278
+ * @param {Quaternion} to
4259
4279
  * @param {number} t
4260
4280
  */
4261
- slerp(other, t) {
4281
+ slerpQuaternions(from, to, t) {
4262
4282
 
4263
- const ax = this.x,
4264
- ay = this.y,
4265
- az = this.z,
4266
- aw = this.w;
4283
+ const ax = from.x,
4284
+ ay = from.y,
4285
+ az = from.z,
4286
+ aw = from.w;
4267
4287
 
4268
- let bx = other.x,
4269
- by = other.y,
4270
- bz = other.z,
4271
- bw = other.w;
4288
+ let bx = to.x,
4289
+ by = to.y,
4290
+ bz = to.z,
4291
+ bw = to.w;
4272
4292
 
4273
4293
  let omega, cosom, sinom, scale0, scale1;
4274
4294
 
@@ -4306,6 +4326,16 @@ let Quaternion$1 = class Quaternion {
4306
4326
  this.set(_x, _y, _z, _w);
4307
4327
  }
4308
4328
 
4329
+
4330
+ /**
4331
+ * @see https://github.com/toji/gl-matrix/blob/master/src/gl-matrix/quat.js
4332
+ * @param {Quaternion} other
4333
+ * @param {number} t
4334
+ */
4335
+ slerp(other, t) {
4336
+ this.slerpQuaternions(this, other, t);
4337
+ }
4338
+
4309
4339
  /**
4310
4340
  * @see https://github.com/gareth-cross/quat/blob/master/include/quaternion.hpp
4311
4341
  * TODO implement
@@ -4587,9 +4617,9 @@ let Quaternion$1 = class Quaternion {
4587
4617
 
4588
4618
  /**
4589
4619
  *
4590
- * @param {number} x
4591
- * @param {number} y
4592
- * @param {number} z
4620
+ * @param {number} x in radians
4621
+ * @param {number} y in radians
4622
+ * @param {number} z in radians
4593
4623
  * @returns {Quaternion}
4594
4624
  */
4595
4625
  static fromEulerAngles(x, y, z) {
@@ -4616,9 +4646,9 @@ let Quaternion$1 = class Quaternion {
4616
4646
  result.copy(to);
4617
4647
  } else {
4618
4648
  // clamp to 1, to make sure we don't overshoot
4619
- const t = min2(1, max_delta / angle);
4649
+ const t = clamp01(max_delta / angle);
4620
4650
 
4621
- from.slerp(to, t);
4651
+ result.slerpQuaternions(from, to, t);
4622
4652
  }
4623
4653
 
4624
4654
  }
@@ -5001,6 +5031,24 @@ class Transform {
5001
5031
  toString() {
5002
5032
  return `{ position: ${this.position}, rotation: ${this.rotation}, scale: ${this.scale} }`;
5003
5033
  }
5034
+
5035
+ /**
5036
+ * @deprecated use {@link Quaternion.rotateTowards} instead
5037
+ * @param {Quaternion} sourceQuaternion
5038
+ * @param {Vector3} targetVector
5039
+ * @param {Number} limit
5040
+ */
5041
+ static adjustRotation(
5042
+ sourceQuaternion,
5043
+ targetVector,
5044
+ limit = Infinity
5045
+ ) {
5046
+ const q = new Quaternion$1();
5047
+
5048
+ q.lookRotation(targetVector);
5049
+
5050
+ sourceQuaternion.rotateTowards(q, limit);
5051
+ }
5004
5052
  }
5005
5053
 
5006
5054
  /**
@@ -5013,22 +5061,7 @@ Transform.typeName = "Transform";
5013
5061
  * @readonly
5014
5062
  * @type {boolean}
5015
5063
  */
5016
- Transform.prototype.isTransform = true;
5017
-
5018
-
5019
- /**
5020
- * @deprecated use {@link Quaternion.rotateTowards} instead
5021
- * @param {Quaternion} sourceQuaternion
5022
- * @param {Vector3} targetVector
5023
- * @param {Number} limit
5024
- */
5025
- Transform.adjustRotation = function (sourceQuaternion, targetVector, limit = Infinity) {
5026
- const q = new Quaternion$1();
5027
-
5028
- q.lookRotation(targetVector);
5029
-
5030
- sourceQuaternion.rotateTowards(q, limit);
5031
- };
5064
+ Transform.prototype.isTransform = true;
5032
5065
 
5033
5066
  /**
5034
5067
  * Common utilities
@@ -47275,6 +47308,16 @@ function max2(a, b) {
47275
47308
  return a < b ? b : a;
47276
47309
  }
47277
47310
 
47311
+ /**
47312
+ * Returns lowest value out of 2 supplied
47313
+ * @param {number} a
47314
+ * @param {number} b
47315
+ * @returns {number}
47316
+ */
47317
+ function min2(a, b) {
47318
+ return a < b ? a : b;
47319
+ }
47320
+
47278
47321
  /**
47279
47322
  *
47280
47323
  * @param {number} x
@@ -53300,23 +53343,6 @@ function bvh_query_leaves_ray(
53300
53343
  return result_cursor - result_offset;
53301
53344
  }
53302
53345
 
53303
- /**
53304
- * Clamps a value to 0..1 range
53305
- * Same as `clamp(value, 0, 1)`
53306
- * Works the same as `saturate` function in GLSL
53307
- * @param {number} value
53308
- * @returns {number}
53309
- */
53310
- function clamp01(value) {
53311
- if (value < 0) {
53312
- return 0;
53313
- } else if (value > 1) {
53314
- return 1;
53315
- } else {
53316
- return value;
53317
- }
53318
- }
53319
-
53320
53346
  /**
53321
53347
  * Returns lowest value out of 3 supplied
53322
53348
  * @param {number} a
@@ -70086,7 +70112,7 @@ BitSet.prototype.nextSetBit = function (fromIndex) {
70086
70112
 
70087
70113
 
70088
70114
  //scan the rest of the words
70089
- const word_count = bit_length / 32;
70115
+ const word_count = (bit_length + 31) >> 5; // Math.ceil(x /32)
70090
70116
  for (; word_index < word_count; word_index++) {
70091
70117
  word = data[word_index];
70092
70118
 
@@ -70122,8 +70148,6 @@ BitSet.prototype.nextClearBit = function (fromIndex) {
70122
70148
  // treat first word specially, as we may need to mask out portion of a word to skip certain number of bits
70123
70149
  let bit_index = fromIndex & 31;
70124
70150
 
70125
- const set_length = this.__length;
70126
- const word_count = set_length / 32;
70127
70151
  const data = this.__data_uint32;
70128
70152
 
70129
70153
  if (bit_index !== 0) {
@@ -70143,6 +70167,8 @@ BitSet.prototype.nextClearBit = function (fromIndex) {
70143
70167
 
70144
70168
  word_index++;
70145
70169
  }
70170
+ const set_length = this.__length;
70171
+ const word_count = (set_length + 31) >> 5; // Math.ceil(x /32)
70146
70172
 
70147
70173
  //scan the rest
70148
70174
  for (; word_index < word_count; word_index++) {
@@ -113611,12 +113637,13 @@ function resolvePathByArray(object, parts, missingPropertyHandler) {
113611
113637
  /**
113612
113638
  *
113613
113639
  * @param {object} object
113614
- * @param {string} path
113640
+ * @param {string} path separated with forward slash "/"
113615
113641
  * @param {function} [missingPropertyHandler] Allows custom handling of missing properties
113616
113642
  * @returns {*}
113617
113643
  * @throws {Error} if a path can not be resolved
113618
113644
  */
113619
113645
  function resolvePath(object, path, missingPropertyHandler) {
113646
+
113620
113647
  const parts = path.split("/");
113621
113648
 
113622
113649
  return resolvePathByArray(object, parts, missingPropertyHandler);
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.94.2",
8
+ "version": "2.94.4",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -53,6 +53,12 @@ export namespace assert {
53
53
  * @param {string} [name]
54
54
  */
55
55
  export function isFunction(value: any, name?: string): void;
56
+ /**
57
+ *
58
+ * @param {Object|*} value
59
+ * @param {string} [name]
60
+ */
61
+ export function isObject(value: any, name?: string): void;
56
62
  /**
57
63
  *
58
64
  * @param {number|*} value
@@ -1 +1 @@
1
- {"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../../src/core/assert.js"],"names":[],"mappings":"AA6BA,6CAIC;;IAsJD;;;;;OAKG;IACH,kEAQC;;;;;;;;;;;;;;;IAmBD;;;;;;OAMG;IACH,uGAGC;IAGD;;;;OAIG;IACH,0DAMC;IAED;;;;OAIG;IACH,0DAMC;IAED;;;;OAIG;IACH,2DAMC;IAED;;;;OAIG;IACH,4DAMC;IAED;;;;OAIG;IACH,2DAMC;IAED;;;;OAIG;IACH,sEAMC;IAED;;;;OAIG;IACH,4DAKC;IAED;;;;OAIG;IACH,+EAKC;IAGD;;;;OAIG;IACH,yDAMC;IAED;;;;OAIG;IACH,wDAIC;IAED;;;;OAIG;IACH,yDAMC;IAED;;;;OAIG;IACH,2DAIC;IAED;;;;OAIG;IACH,mEAIC;IAED;;;;;OAKG;IACH,2EAgBC;;AAlZD,wDAEC;AAED,6CAEC;AAbD,qDAKC;AAUD;;;;;GAKG;AACH,kCAJW,MAAM,KACN,MAAM,MACN,MAAM,QAIhB;AAQD;;;;;GAKG;AACH,gCAJW,MAAM,KACN,MAAM,MACN,MAAM,QAiBhB;AAyBD;;;;;GAKG;AACH,uCAJW,MAAM,KACN,MAAM,MACN,MAAM,QAiBhB;AA5CD;;;;;GAKG;AACH,6BAJW,MAAM,KACN,MAAM,MACN,MAAM,QAiBhB;AAyBD;;;;;GAKG;AACH,oCAJW,MAAM,KACN,MAAM,MACN,MAAM,QAiBhB;AAKD;;;;;GAKG;AACH,0CAHW,MAAM,cACN,MAAM,QAehB;AAED;;;;;GAKG;AACH,iEAFW,MAAM,QAIhB;AAED;;;;;GAKG;AACH,mEAFW,MAAM,QAIhB;AAED;;;;;GAKG;AACH,+IAFW,MAAM,QAMhB"}
1
+ {"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../../src/core/assert.js"],"names":[],"mappings":"AA6BA,6CAIC;;IAsJD;;;;;OAKG;IACH,kEAQC;;;;;;;;;;;;;;;IAmBD;;;;;;OAMG;IACH,uGAGC;IAGD;;;;OAIG;IACH,0DAMC;IAED;;;;OAIG;IACH,0DAMC;IAED;;;;OAIG;IACH,2DAMC;IAED;;;;OAIG;IACH,4DAMC;IAED;;;;OAIG;IACH,0DAMC;IAED;;;;OAIG;IACH,2DAMC;IAED;;;;OAIG;IACH,sEAMC;IAED;;;;OAIG;IACH,4DAKC;IAED;;;;OAIG;IACH,+EAKC;IAGD;;;;OAIG;IACH,yDAMC;IAED;;;;OAIG;IACH,wDAIC;IAED;;;;OAIG;IACH,yDAMC;IAED;;;;OAIG;IACH,2DAIC;IAED;;;;OAIG;IACH,mEAIC;IAED;;;;;OAKG;IACH,2EAgBC;;AA/ZD,wDAEC;AAED,6CAEC;AAbD,qDAKC;AAUD;;;;;GAKG;AACH,kCAJW,MAAM,KACN,MAAM,MACN,MAAM,QAIhB;AAQD;;;;;GAKG;AACH,gCAJW,MAAM,KACN,MAAM,MACN,MAAM,QAiBhB;AAyBD;;;;;GAKG;AACH,uCAJW,MAAM,KACN,MAAM,MACN,MAAM,QAiBhB;AA5CD;;;;;GAKG;AACH,6BAJW,MAAM,KACN,MAAM,MACN,MAAM,QAiBhB;AAyBD;;;;;GAKG;AACH,oCAJW,MAAM,KACN,MAAM,MACN,MAAM,QAiBhB;AAKD;;;;;GAKG;AACH,0CAHW,MAAM,cACN,MAAM,QAehB;AAED;;;;;GAKG;AACH,iEAFW,MAAM,QAIhB;AAED;;;;;GAKG;AACH,mEAFW,MAAM,QAIhB;AAED;;;;;GAKG;AACH,+IAFW,MAAM,QAMhB"}
@@ -279,6 +279,19 @@ assert.isFunction = function (value, name = 'value') {
279
279
  }
280
280
  };
281
281
 
282
+ /**
283
+ *
284
+ * @param {Object|*} value
285
+ * @param {string} [name]
286
+ */
287
+ assert.isObject = function (value, name = 'value') {
288
+ const typeofValue = typeof value;
289
+
290
+ if (typeofValue !== 'object') {
291
+ throw new Error(`expected ${name} to be an object, instead was '${typeofValue}'(=${value})`);
292
+ }
293
+ };
294
+
282
295
  /**
283
296
  *
284
297
  * @param {number|*} value
@@ -286,7 +286,7 @@ BitSet.prototype.nextSetBit = function (fromIndex) {
286
286
 
287
287
 
288
288
  //scan the rest of the words
289
- const word_count = bit_length / 32;
289
+ const word_count = (bit_length + 31) >> 5; // Math.ceil(x /32)
290
290
  for (; word_index < word_count; word_index++) {
291
291
  word = data[word_index];
292
292
 
@@ -322,8 +322,6 @@ BitSet.prototype.nextClearBit = function (fromIndex) {
322
322
  // treat first word specially, as we may need to mask out portion of a word to skip certain number of bits
323
323
  let bit_index = fromIndex & 31;
324
324
 
325
- const set_length = this.__length;
326
- const word_count = set_length / 32;
327
325
  const data = this.__data_uint32;
328
326
 
329
327
  if (bit_index !== 0) {
@@ -343,6 +341,8 @@ BitSet.prototype.nextClearBit = function (fromIndex) {
343
341
 
344
342
  word_index++;
345
343
  }
344
+ const set_length = this.__length;
345
+ const word_count = (set_length + 31) >> 5; // Math.ceil(x /32)
346
346
 
347
347
  //scan the rest
348
348
  for (; word_index < word_count; word_index++) {
@@ -1 +1 @@
1
- {"version":3,"file":"Quaternion.d.ts","sourceRoot":"","sources":["../../../../src/core/geom/Quaternion.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Quaternion.d.ts","sourceRoot":"","sources":["../../../../src/core/geom/Quaternion.js"],"names":[],"mappings":"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"}
@@ -6,10 +6,10 @@
6
6
  import { assert } from "../assert.js";
7
7
  import Signal from "../events/signal/Signal.js";
8
8
  import { clamp } from "../math/clamp.js";
9
+ import { clamp01 } from "../math/clamp01.js";
9
10
  import { EPSILON } from "../math/EPSILON.js";
10
11
  import { epsilonEquals } from "../math/epsilonEquals.js";
11
12
  import { lerp } from "../math/lerp.js";
12
- import { min2 } from "../math/min2.js";
13
13
  import { computeHashFloat } from "../primitives/numbers/computeHashFloat.js";
14
14
  import { quat_decode_from_uint32 } from "./3d/quaternion/quat_decode_from_uint32.js";
15
15
  import { quat_encode_to_uint32 } from "./3d/quaternion/quat_encode_to_uint32.js";
@@ -1152,24 +1152,24 @@ class Quaternion {
1152
1152
  this.set(x, y, z, w);
1153
1153
  }
1154
1154
 
1155
-
1156
1155
  /**
1157
- * @see https://github.com/toji/gl-matrix/blob/master/src/gl-matrix/quat.js
1158
- * @param {Quaternion} other
1156
+ *
1157
+ * @param {Quaternion} from
1158
+ * @param {Quaternion} to
1159
1159
  * @param {number} t
1160
1160
  */
1161
- slerp(other, t) {
1161
+ slerpQuaternions(from, to, t) {
1162
1162
  assert.isNumber(t, 't');
1163
1163
 
1164
- const ax = this.x,
1165
- ay = this.y,
1166
- az = this.z,
1167
- aw = this.w;
1164
+ const ax = from.x,
1165
+ ay = from.y,
1166
+ az = from.z,
1167
+ aw = from.w;
1168
1168
 
1169
- let bx = other.x,
1170
- by = other.y,
1171
- bz = other.z,
1172
- bw = other.w;
1169
+ let bx = to.x,
1170
+ by = to.y,
1171
+ bz = to.z,
1172
+ bw = to.w;
1173
1173
 
1174
1174
  let omega, cosom, sinom, scale0, scale1;
1175
1175
 
@@ -1207,6 +1207,16 @@ class Quaternion {
1207
1207
  this.set(_x, _y, _z, _w);
1208
1208
  }
1209
1209
 
1210
+
1211
+ /**
1212
+ * @see https://github.com/toji/gl-matrix/blob/master/src/gl-matrix/quat.js
1213
+ * @param {Quaternion} other
1214
+ * @param {number} t
1215
+ */
1216
+ slerp(other, t) {
1217
+ this.slerpQuaternions(this, other, t);
1218
+ }
1219
+
1210
1220
  /**
1211
1221
  * @see https://github.com/gareth-cross/quat/blob/master/include/quaternion.hpp
1212
1222
  * TODO implement
@@ -1497,9 +1507,9 @@ class Quaternion {
1497
1507
 
1498
1508
  /**
1499
1509
  *
1500
- * @param {number} x
1501
- * @param {number} y
1502
- * @param {number} z
1510
+ * @param {number} x in radians
1511
+ * @param {number} y in radians
1512
+ * @param {number} z in radians
1503
1513
  * @returns {Quaternion}
1504
1514
  */
1505
1515
  static fromEulerAngles(x, y, z) {
@@ -1519,6 +1529,7 @@ class Quaternion {
1519
1529
  */
1520
1530
  static rotateTowards(result, from, to, max_delta) {
1521
1531
  assert.isNumber(max_delta, 'max_delta');
1532
+ assert.notNaN(max_delta, 'max_delta');
1522
1533
 
1523
1534
  const angle = from.angleTo(to);
1524
1535
 
@@ -1527,9 +1538,9 @@ class Quaternion {
1527
1538
  result.copy(to);
1528
1539
  } else {
1529
1540
  // clamp to 1, to make sure we don't overshoot
1530
- const t = min2(1, max_delta / angle);
1541
+ const t = clamp01(max_delta / angle);
1531
1542
 
1532
- from.slerp(to, t);
1543
+ result.slerpQuaternions(from, to, t);
1533
1544
  }
1534
1545
 
1535
1546
  }
@@ -1,6 +1,7 @@
1
+ import { DEG_TO_RAD } from "../math/DEG_TO_RAD.js";
2
+ import { decode_octahedron_to_unit } from "./3d/normal/octahedron/decode_octahedron_to_unit.js";
1
3
  import Quaternion from "./Quaternion.js";
2
4
  import Vector3 from "./Vector3.js";
3
- import { decode_octahedron_to_unit } from "./3d/normal/octahedron/decode_octahedron_to_unit.js";
4
5
 
5
6
  /**
6
7
  *
@@ -401,3 +402,28 @@ test("angleTo between identical quaternions should be 0", () => {
401
402
 
402
403
  expect(a.angleTo(b)).toBeCloseTo(0);
403
404
  });
405
+
406
+
407
+ test("rotateTowards", () => {
408
+
409
+ const a = Quaternion.fromEulerAngles(30 * DEG_TO_RAD, 0, 0);
410
+ const b = Quaternion.fromEulerAngles(60 * DEG_TO_RAD, 0, 0);
411
+
412
+ const result = new Quaternion();
413
+
414
+ Quaternion.rotateTowards(result, a, b, 9 * DEG_TO_RAD);
415
+
416
+ expect(result.angleTo(a)).toBeCloseTo(9 * DEG_TO_RAD);
417
+
418
+ Quaternion.rotateTowards(result, a, b, 0);
419
+
420
+ expect(result.equals(a)).toBe(true);
421
+
422
+ Quaternion.rotateTowards(result, a, b, Infinity);
423
+
424
+ expect(result.equals(b)).toBe(true);
425
+
426
+ Quaternion.rotateTowards(result, a, b, -10);
427
+
428
+ expect(result.roughlyEquals(a)).toBe(true);
429
+ });
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  *
3
3
  * @param {object} object
4
- * @param {string} path
4
+ * @param {string} path separated with forward slash "/"
5
5
  * @param {function} [missingPropertyHandler] Allows custom handling of missing properties
6
6
  * @returns {*}
7
7
  * @throws {Error} if a path can not be resolved
@@ -1 +1 @@
1
- {"version":3,"file":"resolvePath.d.ts","sourceRoot":"","sources":["../../../../src/core/json/resolvePath.js"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,oCANW,MAAM,QACN,MAAM,0CAShB"}
1
+ {"version":3,"file":"resolvePath.d.ts","sourceRoot":"","sources":["../../../../src/core/json/resolvePath.js"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,oCANW,MAAM,QACN,MAAM,0CAYhB"}
@@ -1,15 +1,19 @@
1
+ import { assert } from "../assert.js";
1
2
  import { resolvePathByArray } from "./resolvePathByArray.js";
2
3
 
3
4
 
4
5
  /**
5
6
  *
6
7
  * @param {object} object
7
- * @param {string} path
8
+ * @param {string} path separated with forward slash "/"
8
9
  * @param {function} [missingPropertyHandler] Allows custom handling of missing properties
9
10
  * @returns {*}
10
11
  * @throws {Error} if a path can not be resolved
11
12
  */
12
13
  export function resolvePath(object, path, missingPropertyHandler) {
14
+ assert.isString(path, 'path');
15
+ assert.isObject(object, "object");
16
+
13
17
  const parts = path.split("/");
14
18
 
15
19
  return resolvePathByArray(object, parts, missingPropertyHandler);
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Branchless fast integer Absolute value function.
3
+ * Same as Math.abs(x) but for integer values only.
4
+ * Only valid for integers up to and including 32 bit.
5
+ * @param {number} x
6
+ * @return {number}
7
+ */
8
+ export function iabs(x: number): number;
9
+ //# sourceMappingURL=iabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iabs.d.ts","sourceRoot":"","sources":["../../../../src/core/math/iabs.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAHW,MAAM,GACL,MAAM,CAOjB"}
@@ -0,0 +1,15 @@
1
+ import { assert } from "../assert.js";
2
+
3
+ /**
4
+ * Branchless fast integer Absolute value function.
5
+ * Same as Math.abs(x) but for integer values only.
6
+ * Only valid for integers up to and including 32 bit.
7
+ * @param {number} x
8
+ * @return {number}
9
+ */
10
+ export function iabs(x) {
11
+ // adapted from https://graphics.stanford.edu/~seander/bithacks.html
12
+ assert.isInteger(x, 'x');
13
+
14
+ return (x ^ (x >> 31)) - (x >> 31);
15
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=iabs.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iabs.spec.d.ts","sourceRoot":"","sources":["../../../../src/core/math/iabs.spec.js"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import { iabs } from "./iabs.js";
2
+
3
+ test("basics", () => {
4
+ expect(iabs(0)).toBe(0);
5
+ expect(iabs(1)).toBe(1);
6
+ expect(iabs(1023)).toBe(1023);
7
+ expect(iabs(-1)).toBe(1);
8
+ expect(iabs(-1023)).toBe(1023);
9
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"Transform.d.ts","sourceRoot":"","sources":["../../../../../src/engine/ecs/transform/Transform.js"],"names":[],"mappings":"AA0BA;;;GAGG;AACH;IAwQI;;;;OAIG;IACH,4BAFa,SAAS,CAQrB;IAjRD;;;OAGG;IACH,mBAHU,OAAO,CAGe;IAEhC;;;OAGG;IACH,mBAHU,UAAU,CAGkB;IAEtC;;;OAGG;IACH,gBAHU,OAAO,CAGY;IAE7B;;;;OAIG;IACH,iBAFU,YAAY,CAEW;IAEjC;;;;OAIG;IACH,OAFU,MAAM,CAEM;IAOtB;;;;OAIG;IACH,uBAMC;IAED;;;OAGG;IACH,kBAMC;IAED;;;OAGG;IACH,qBAMC;IAED;;;;OAIG;IACH,kDAIC;IAED;;;;OAIG;IACH,oDAIC;IAYD;;;;OAIG;IACH,cAHW,MAAM,GAAC,cAAc,GACnB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,cAAc,GACnB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,cAAc,SACrB,OAAO,QAQjB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,cAAc,GACnB,OAAO,CAInB;IAED;;OAEG;IACH,qBAEC;IAED;;;;OAIG;IACH,eAHW,OAAO,OACP,OAAO,QAmBjB;IAED,0BAwBC;IAED;;;;MAMC;IAED;;;OAGG;IACH,YAFW,SAAS,QAenB;IAED;;;OAGG;IACH,SAFa,SAAS,CAQrB;IAED;;;;OAIG;IACH,cAHW,SAAS,GACP,OAAO,CAMnB;IAED;;;OAGG;IACH,QAFa,MAAM,CAKlB;IAeD;;;;OAIG;IACH,sBAHW,SAAS,KACT,SAAS,QAMnB;IAED;;;OAGG;IACH,eAFW,OAAK,MAAM,EAAE,GAAC,YAAY,QAcpC;IAED;;;OAGG;IACH,kBAFW,MAAM,EAAE,GAAC,YAAY,QAI/B;IAED;;;;;OAKG;IACH,qBAEC;IAED,mBAEC;IASL;;;OAGG;IACH,sBAFU,OAAO,CAEc;;CAZ9B;;kBAIS,MAAM;IAWhB;;;;;OAKG;IACH,mGAMC;;oBArXmB,+BAA+B;uBAD5B,kCAAkC;+BAE1B,qBAAqB"}
1
+ {"version":3,"file":"Transform.d.ts","sourceRoot":"","sources":["../../../../../src/engine/ecs/transform/Transform.js"],"names":[],"mappings":"AA0BA;;;GAGG;AACH;IAwQI;;;;OAIG;IACH,4BAFa,SAAS,CAQrB;IAqDD;;;;;OAKG;IACH,wCAJW,UAAU,gBACV,OAAO,wBAajB;IAtVD;;;OAGG;IACH,mBAHU,OAAO,CAGe;IAEhC;;;OAGG;IACH,mBAHU,UAAU,CAGkB;IAEtC;;;OAGG;IACH,gBAHU,OAAO,CAGY;IAE7B;;;;OAIG;IACH,iBAFU,YAAY,CAEW;IAEjC;;;;OAIG;IACH,OAFU,MAAM,CAEM;IAOtB;;;;OAIG;IACH,uBAMC;IAED;;;OAGG;IACH,kBAMC;IAED;;;OAGG;IACH,qBAMC;IAED;;;;OAIG;IACH,kDAIC;IAED;;;;OAIG;IACH,oDAIC;IAYD;;;;OAIG;IACH,cAHW,MAAM,GAAC,cAAc,GACnB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,cAAc,GACnB,IAAI,CAIhB;IAED;;;;OAIG;IACH,gBAHW,MAAM,GAAC,cAAc,SACrB,OAAO,QAQjB;IAED;;;;OAIG;IACH,cAHW,MAAM,GAAC,cAAc,GACnB,OAAO,CAInB;IAED;;OAEG;IACH,qBAEC;IAED;;;;OAIG;IACH,eAHW,OAAO,OACP,OAAO,QAmBjB;IAED,0BAwBC;IAED;;;;MAMC;IAED;;;OAGG;IACH,YAFW,SAAS,QAenB;IAED;;;OAGG;IACH,SAFa,SAAS,CAQrB;IAED;;;;OAIG;IACH,cAHW,SAAS,GACP,OAAO,CAMnB;IAED;;;OAGG;IACH,QAFa,MAAM,CAKlB;IAeD;;;;OAIG;IACH,sBAHW,SAAS,KACT,SAAS,QAMnB;IAED;;;OAGG;IACH,eAFW,OAAK,MAAM,EAAE,GAAC,YAAY,QAcpC;IAED;;;OAGG;IACH,kBAFW,MAAM,EAAE,GAAC,YAAY,QAI/B;IAED;;;;;OAKG;IACH,qBAEC;IAED,mBAEC;IA2BL;;;OAGG;IACH,sBAFU,OAAO,CAEc;;CAZ9B;;kBAIS,MAAM;;oBAhXI,+BAA+B;uBAD5B,kCAAkC;+BAE1B,qBAAqB"}
@@ -355,6 +355,24 @@ export class Transform {
355
355
  toString() {
356
356
  return `{ position: ${this.position}, rotation: ${this.rotation}, scale: ${this.scale} }`;
357
357
  }
358
+
359
+ /**
360
+ * @deprecated use {@link Quaternion.rotateTowards} instead
361
+ * @param {Quaternion} sourceQuaternion
362
+ * @param {Vector3} targetVector
363
+ * @param {Number} limit
364
+ */
365
+ static adjustRotation(
366
+ sourceQuaternion,
367
+ targetVector,
368
+ limit = Infinity
369
+ ) {
370
+ const q = new Quaternion();
371
+
372
+ q.lookRotation(targetVector);
373
+
374
+ sourceQuaternion.rotateTowards(q, limit);
375
+ }
358
376
  }
359
377
 
360
378
  /**
@@ -370,17 +388,4 @@ Transform.typeName = "Transform";
370
388
  Transform.prototype.isTransform = true;
371
389
 
372
390
 
373
- /**
374
- * @deprecated use {@link Quaternion.rotateTowards} instead
375
- * @param {Quaternion} sourceQuaternion
376
- * @param {Vector3} targetVector
377
- * @param {Number} limit
378
- */
379
- Transform.adjustRotation = function (sourceQuaternion, targetVector, limit = Infinity) {
380
- const q = new Quaternion();
381
-
382
- q.lookRotation(targetVector);
383
-
384
- sourceQuaternion.rotateTowards(q, limit);
385
- };
386
391