@woosh/meep-engine 2.69.0 → 2.71.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 (50) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/bundle-worker-terrain.js +1 -1
  3. package/build/meep.cjs +498 -429
  4. package/build/meep.min.js +1 -1
  5. package/build/meep.module.js +498 -429
  6. package/package.json +1 -1
  7. package/src/core/__module.js +1 -0
  8. package/src/core/binary/BinaryBuffer.js +37 -31
  9. package/src/core/bvh2/binary/2/BinaryUint32BVH.js +21 -24
  10. package/src/core/bvh2/binary/2/BinaryUint32BVH.spec.js +2 -4
  11. package/src/core/geom/3d/cone/compute_bounding_cone_of_2_cones.js +3 -2
  12. package/src/core/geom/3d/morton/v3_morton_encode_bounded.js +34 -0
  13. package/src/core/geom/3d/morton/v3_morton_encode_transformed.js +2 -1
  14. package/src/core/geom/3d/quaternion/quat3_createFromAxisAngle.js +11 -0
  15. package/src/core/geom/3d/quaternion/quat_decode_from_uint32.js +53 -0
  16. package/src/core/geom/3d/quaternion/quat_encode_to_uint32.js +105 -0
  17. package/src/core/geom/Quaternion.js +8 -142
  18. package/src/core/geom/Vector2.js +6 -7
  19. package/src/core/geom/Vector3.js +15 -82
  20. package/src/core/geom/vec3/v3_binary_equality_decode.js +44 -0
  21. package/src/core/geom/vec3/v3_binary_equality_encode.js +47 -0
  22. package/src/core/math/remap.js +5 -1
  23. package/src/core/math/statistics/computeStatisticalPartialMedian.js +1 -1
  24. package/src/core/primitives/numbers/computeHashFloat.js +2 -2
  25. package/src/core/process/task/Task.js +53 -34
  26. package/src/engine/achievements/AchievementManager.js +19 -19
  27. package/src/engine/animation/curve/compression/prototypeCurveCompression.js +6 -6
  28. package/src/engine/animation/curve/draw/build_plot_entity_from_array.js +11 -6
  29. package/src/engine/ecs/dynamic_actions/DynamicActor.js +5 -10
  30. package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +82 -89
  31. package/src/engine/ecs/dynamic_actions/RuleExecution.js +10 -12
  32. package/src/engine/ecs/gui/GUIElement.js +44 -61
  33. package/src/engine/ecs/gui/GUIElementSystem.js +26 -24
  34. package/src/engine/ecs/gui/hud/HeadsUpDisplay.js +12 -15
  35. package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +15 -15
  36. package/src/engine/ecs/gui/parallax/GuiElementParallax.js +3 -3
  37. package/src/engine/ecs/gui/parallax/GuiElementParallaxSystem.js +2 -2
  38. package/src/engine/ecs/gui/position/ViewportPosition.js +5 -50
  39. package/src/engine/ecs/gui/position/ViewportPositionSerializationAdapter.js +42 -0
  40. package/src/engine/ecs/transform/Transform.js +8 -9
  41. package/src/engine/ecs/transform/TransformSerializationAdapter.js +20 -14
  42. package/src/engine/graphics/ecs/mesh/Mesh.js +11 -11
  43. package/src/engine/graphics/impostors/octahedral/prototypeBaker.js +20 -20
  44. package/src/engine/graphics/texture/sprite/prototypeSpriteCutoutGeometry.js +12 -12
  45. package/src/engine/navigation/ecs/components/PathSerializationAdapter.js +1 -4
  46. package/src/core/binary/ValidatingBitSetWrapper.js +0 -81
  47. package/src/core/binary/jsonToStringToByteArray.js +0 -27
  48. package/src/engine/ecs/components/AreaOfEffect.js +0 -12
  49. package/src/engine/ecs/components/Mortality.js +0 -27
  50. package/src/engine/ecs/systems/AreaOfEffectSystem.js +0 -48
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.69.0",
8
+ "version": "2.71.0",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -9,3 +9,4 @@ export * from "./geom/Vector1.js";
9
9
  export * from "./events/signal/Signal.js";
10
10
  export * from "./events/signal/SignalBinding.js";
11
11
  export * from "./geom/Quaternion.js";
12
+ export { quat3_createFromAxisAngle } from "./geom/3d/quaternion/quat3_createFromAxisAngle.js";
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { assert } from "../assert.js";
6
6
  import { array_copy } from "../collection/array/array_copy.js";
7
+ import { typed_array_copy } from "../collection/array/typed/typed_array_copy.js";
7
8
 
8
9
  /**
9
10
  *
@@ -142,8 +143,7 @@ export class BinaryBuffer {
142
143
  const newData = new Uint8Array(capacity);
143
144
 
144
145
  //copy old data
145
- const copyLength = Math.min(newData.length, oldData.length);
146
- newData.set(oldData.subarray(0, copyLength), 0);
146
+ typed_array_copy(oldData, newData);
147
147
 
148
148
  this.data = newData.buffer;
149
149
  this.__data_uint8 = newData;
@@ -152,15 +152,24 @@ export class BinaryBuffer {
152
152
  this.capacity = capacity;
153
153
  }
154
154
 
155
- ensureCapacity(minCapacity) {
156
- if (this.capacity < minCapacity) {
157
- const newCapacity = Math.ceil(Math.max(
158
- minCapacity,
159
- this.capacity * this.__growFactor,
160
- this.capacity + MIN_GROWTH_STEP
161
- ));
162
- this.setCapacity(newCapacity);
155
+ /**
156
+ *
157
+ * @param {number} min_capacity
158
+ */
159
+ ensureCapacity(min_capacity) {
160
+ const existing_capacity = this.capacity;
161
+
162
+ if (existing_capacity >= min_capacity) {
163
+ return;
163
164
  }
165
+
166
+ const new_capacity = Math.ceil(Math.max(
167
+ min_capacity,
168
+ existing_capacity * this.__growFactor,
169
+ existing_capacity + MIN_GROWTH_STEP
170
+ ));
171
+
172
+ this.setCapacity(new_capacity);
164
173
  }
165
174
 
166
175
  readFloat32() {
@@ -825,16 +834,14 @@ export class BinaryBuffer {
825
834
  //mark non-NULL
826
835
  this.writeUint32(len);
827
836
 
828
- const startPosition = this.position;
829
-
830
- let at = startPosition; // output position
831
-
832
- let tlen = Math.max(32, len + (len >> 1) + 7); // 1.5x size
837
+ let cursor = this.position; // output position
833
838
 
834
- this.ensureCapacity(tlen + at);
839
+ const expected_byte_size = Math.max(32, len + (len >> 1) + 7); // 1.5x size
835
840
 
836
- let target = this.__data_uint8; // ... but at 8 byte offset
841
+ this.ensureCapacity(expected_byte_size + cursor);
837
842
 
843
+ let target = this.__data_uint8;
844
+ let capacity = this.capacity;
838
845
 
839
846
  while (pos < len) {
840
847
  let value = string.charCodeAt(pos++);
@@ -853,37 +860,36 @@ export class BinaryBuffer {
853
860
  }
854
861
 
855
862
  // expand the buffer if we couldn't write 4 bytes
856
- if (at + 4 > this.capacity) {
857
- tlen += 8; // minimum extra
858
- tlen *= (1.0 + (pos / len) * 2); // take 2x the remaining
859
- tlen = (tlen >> 3) << 3; // 8 byte offset
863
+ if (cursor + 4 > capacity) {
860
864
 
861
- this.ensureCapacity(tlen + startPosition);
865
+ this.ensureCapacity(cursor + 4);
862
866
 
867
+ // rebind variables
868
+ capacity = this.capacity;
863
869
  target = this.__data_uint8;
864
870
  }
865
871
 
866
872
  if ((value & 0xffffff80) === 0) { // 1-byte
867
- target[at++] = value; // ASCII
873
+ target[cursor++] = value; // ASCII
868
874
  continue;
869
875
  } else if ((value & 0xfffff800) === 0) { // 2-byte
870
- target[at++] = ((value >> 6) & 0x1f) | 0xc0;
876
+ target[cursor++] = ((value >> 6) & 0x1f) | 0xc0;
871
877
  } else if ((value & 0xffff0000) === 0) { // 3-byte
872
- target[at++] = ((value >> 12) & 0x0f) | 0xe0;
873
- target[at++] = ((value >> 6) & 0x3f) | 0x80;
878
+ target[cursor++] = ((value >> 12) & 0x0f) | 0xe0;
879
+ target[cursor++] = ((value >> 6) & 0x3f) | 0x80;
874
880
  } else if ((value & 0xffe00000) === 0) { // 4-byte
875
- target[at++] = ((value >> 18) & 0x07) | 0xf0;
876
- target[at++] = ((value >> 12) & 0x3f) | 0x80;
877
- target[at++] = ((value >> 6) & 0x3f) | 0x80;
881
+ target[cursor++] = ((value >> 18) & 0x07) | 0xf0;
882
+ target[cursor++] = ((value >> 12) & 0x3f) | 0x80;
883
+ target[cursor++] = ((value >> 6) & 0x3f) | 0x80;
878
884
  } else {
879
885
  // FIXME: do we care
880
886
  continue;
881
887
  }
882
888
 
883
- target[at++] = (value & 0x3f) | 0x80;
889
+ target[cursor++] = (value & 0x3f) | 0x80;
884
890
  }
885
891
 
886
- this.position = at;
892
+ this.position = cursor;
887
893
  }
888
894
 
889
895
  /**
@@ -2,10 +2,11 @@ import { assert } from "../../../assert.js";
2
2
  import { ceilPowerOfTwo } from "../../../binary/operations/ceilPowerOfTwo.js";
3
3
  import { array_copy } from "../../../collection/array/array_copy.js";
4
4
  import { array_swap } from "../../../collection/array/array_swap.js";
5
+ import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
5
6
  import { aabb3_array_combine } from "../../../geom/3d/aabb/aabb3_array_combine.js";
6
7
  import { aabb3_array_set } from "../../../geom/3d/aabb/aabb3_array_set.js";
7
8
  import { aabb3_compute_half_surface_area } from "../../../geom/3d/aabb/aabb3_compute_half_surface_area.js";
8
- import { mortonEncode_magicbits } from "../../../geom/3d/morton/mortonEncode_magicbits.js";
9
+ import { v3_morton_encode_bounded } from "../../../geom/3d/morton/v3_morton_encode_bounded.js";
9
10
  import { max2 } from "../../../math/max2.js";
10
11
  import { max3 } from "../../../math/max3.js";
11
12
  import { min2 } from "../../../math/min2.js";
@@ -54,10 +55,10 @@ function copy_box_zero_size(data, destination, source) {
54
55
  * Assumes data will be normalized to 0...1 value range
55
56
  * @param {Float32Array} data
56
57
  * @param {number} address
57
- * @param {number[]} matrix
58
+ * @param {number[]} bounds
58
59
  * @returns {number}
59
60
  */
60
- function build_morton(data, address, matrix) {
61
+ function build_morton(data, address, bounds) {
61
62
 
62
63
  const x0 = data[address];
63
64
  const y0 = data[address + 1];
@@ -66,17 +67,15 @@ function build_morton(data, address, matrix) {
66
67
  const y1 = data[address + 4];
67
68
  const z1 = data[address + 5];
68
69
 
69
- const cx = (x0 + x1) / 2;
70
- const cy = (y0 + y1) / 2;
71
- const cz = (z0 + z1) / 2;
70
+ const cx = (x0 + x1) * 0.5;
71
+ const cy = (y0 + y1) * 0.5;
72
+ const cz = (z0 + z1) * 0.5;
72
73
 
73
- return mortonEncode_magicbits(cx, cy, cz);
74
- // return v3_morton_encode_transformed(cx, cy, cz, matrix);
74
+ return v3_morton_encode_bounded(cx, cy, cz, bounds);
75
75
 
76
76
  }
77
77
 
78
- const scratch_box_0 = new Float32Array(18);
79
- const stack = [];
78
+ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
80
79
 
81
80
  export class BinaryUint32BVH {
82
81
  /**
@@ -307,17 +306,15 @@ export class BinaryUint32BVH {
307
306
  * @private
308
307
  */
309
308
  __compute_bounds_area_of_3_boxes(a, b, c) {
310
- this.readBounds(a, scratch_box_0, 0);
311
- this.readBounds(b, scratch_box_0, 6);
312
- this.readBounds(c, scratch_box_0, 12);
309
+ const float32 = this.__data_float32;
313
310
 
314
- const x0 = min3(scratch_box_0[0], scratch_box_0[6], scratch_box_0[12]);
315
- const y0 = min3(scratch_box_0[1], scratch_box_0[7], scratch_box_0[13]);
316
- const z0 = min3(scratch_box_0[2], scratch_box_0[8], scratch_box_0[14]);
311
+ const x0 = min3(float32[a + 0], float32[b + 0], float32[c + 0]);
312
+ const y0 = min3(float32[a + 1], float32[b + 1], float32[c + 1]);
313
+ const z0 = min3(float32[a + 2], float32[b + 2], float32[c + 2]);
317
314
 
318
- const x1 = max3(scratch_box_0[3], scratch_box_0[9], scratch_box_0[15]);
319
- const y1 = max3(scratch_box_0[4], scratch_box_0[10], scratch_box_0[16]);
320
- const z1 = max3(scratch_box_0[5], scratch_box_0[11], scratch_box_0[17]);
315
+ const x1 = max3(float32[a + 3], float32[b + 3], float32[c + 3]);
316
+ const y1 = max3(float32[a + 4], float32[b + 4], float32[c + 4]);
317
+ const z1 = max3(float32[a + 5], float32[b + 5], float32[c + 5]);
321
318
 
322
319
  return aabb3_compute_half_surface_area(x0, y0, z0, x1, y1, z1);
323
320
  }
@@ -369,9 +366,9 @@ export class BinaryUint32BVH {
369
366
 
370
367
  /**
371
368
  * Sort leaf nodes according to their morton codes
372
- * @param {number[]} projection
369
+ * @param {number[]} bounds
373
370
  */
374
- sort_morton(projection) {
371
+ sort_morton(bounds) {
375
372
 
376
373
  const leaf_block_address = this.__node_count_binary * BVH_BINARY_NODE_SIZE;
377
374
 
@@ -401,15 +398,15 @@ export class BinaryUint32BVH {
401
398
 
402
399
  const pivot_address = pivotIndex * BVH_LEAF_NODE_SIZE + leaf_block_address;
403
400
 
404
- const pivot = build_morton(data, pivot_address, projection);
401
+ const pivot = build_morton(data, pivot_address, bounds);
405
402
 
406
403
  /* partition */
407
404
  while (i <= j) {
408
- while (build_morton(data, i * BVH_LEAF_NODE_SIZE + leaf_block_address, projection) < pivot) {
405
+ while (build_morton(data, i * BVH_LEAF_NODE_SIZE + leaf_block_address, bounds) < pivot) {
409
406
  i++;
410
407
  }
411
408
 
412
- while (build_morton(data, j * BVH_LEAF_NODE_SIZE + leaf_block_address, projection) > pivot) {
409
+ while (build_morton(data, j * BVH_LEAF_NODE_SIZE + leaf_block_address, bounds) > pivot) {
413
410
  j--;
414
411
  }
415
412
 
@@ -129,10 +129,8 @@ test('4 node sorted build', () => {
129
129
  bvh.setLeafData(3, 13, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6);
130
130
 
131
131
  bvh.sort_morton([
132
- 1, 0, 0, 0,
133
- 0, 1, 0, 0,
134
- 0, 0, 1, 0,
135
- 0, 0, 0, 1
132
+ 0, 0, 0,
133
+ 1, 1, 1
136
134
  ]);
137
135
  bvh.build();
138
136
  });
@@ -1,9 +1,10 @@
1
1
  //
2
2
 
3
3
 
4
- import Vector3 from "../../Vector3.js";
5
- import Quaternion, { quat3_createFromAxisAngle } from "../../Quaternion.js";
6
4
  import { max2 } from "../../../math/max2.js";
5
+ import Quaternion from "../../Quaternion.js";
6
+ import Vector3 from "../../Vector3.js";
7
+ import { quat3_createFromAxisAngle } from "../quaternion/quat3_createFromAxisAngle.js";
7
8
 
8
9
  const tangent = new Vector3();
9
10
 
@@ -0,0 +1,34 @@
1
+ import { mortonEncode_magicbits } from "./mortonEncode_magicbits.js";
2
+
3
+ /**
4
+ * @param {number} x
5
+ * @param {number} y
6
+ * @param {number} z
7
+ * @param {number[]} bounds
8
+ * @returns {number}
9
+ */
10
+ export function v3_morton_encode_bounded(x, y, z, bounds) {
11
+
12
+ const bounds_x0 = bounds[0];
13
+ const bounds_y0 = bounds[1];
14
+ const bounds_z0 = bounds[2];
15
+
16
+ const bounds_x1 = bounds[3];
17
+ const bounds_y1 = bounds[4];
18
+ const bounds_z1 = bounds[5];
19
+
20
+ const bounds_span_x = bounds_x1 - bounds_x0;
21
+ const bounds_span_y = bounds_y1 - bounds_y0;
22
+ const bounds_span_z = bounds_z1 - bounds_z0;
23
+
24
+ // scale to 10 bits
25
+ const ndc_x = 1023 * (x - bounds_x0) / bounds_span_x;
26
+ const ndc_y = 1023 * (y - bounds_y0) / bounds_span_y;
27
+ const ndc_z = 1023 * (z - bounds_z0) / bounds_span_z;
28
+
29
+ return mortonEncode_magicbits(
30
+ Math.round(ndc_x),
31
+ Math.round(ndc_y),
32
+ Math.round(ndc_z)
33
+ );
34
+ }
@@ -1,5 +1,5 @@
1
- import { mortonEncode_magicbits } from "./mortonEncode_magicbits.js";
2
1
  import { clamp } from "../../../math/clamp.js";
2
+ import { mortonEncode_magicbits } from "./mortonEncode_magicbits.js";
3
3
 
4
4
  /**
5
5
  * Assumes that coordinates will be mapped to -1..1 range after transform
@@ -35,3 +35,4 @@ export function v3_morton_encode_transformed(x, y, z, matrix) {
35
35
  Math.round(pz)
36
36
  );
37
37
  }
38
+
@@ -0,0 +1,11 @@
1
+ /**
2
+ * just in case you need that function also
3
+ * @param {Vector3} axis
4
+ * @param {number} angle
5
+ * @param {Quaternion} result
6
+ */
7
+ export function quat3_createFromAxisAngle(axis, angle, result) {
8
+ const halfAngle = angle * .5;
9
+ const s = Math.sin(halfAngle);
10
+ result.set(axis.x * s, axis.y * s, axis.z * s, Math.cos(halfAngle));
11
+ }
@@ -0,0 +1,53 @@
1
+ const K = Math.SQRT1_2 / 511;
2
+
3
+ /**
4
+ * Based on GDC talk from Bungie on destiny, compressing quaternions for animation
5
+ * @param {number[]} output
6
+ * @param {number} output_offset
7
+ * @param {number} value
8
+ */
9
+ export function quat_decode_from_uint32(output, output_offset, value) {
10
+ //read components
11
+ const max = value & 0x3;
12
+
13
+ const iv0 = (value >> 2) & 0x3FF;
14
+ const iv1 = (value >> 12) & 0x3FF;
15
+ const iv2 = (value >> 22) & 0x3FF;
16
+
17
+ //scale components back to quaternion range
18
+ const v0 = iv0 * K - Math.SQRT1_2;
19
+ const v1 = iv1 * K - Math.SQRT1_2;
20
+ const v2 = iv2 * K - Math.SQRT1_2;
21
+
22
+ //restore dropped component using quaternion identity: x^2 + y^2 + z^2 + w^2 = 1
23
+ const dropped_2 = 1 - v0 * v0 - v1 * v1 - v2 * v2;
24
+ const dropped = Math.sqrt(dropped_2);
25
+
26
+ let x, y, z, w;
27
+ if (max === 0) {
28
+ x = dropped
29
+ y = v0
30
+ z = v1
31
+ w = v2
32
+ } else if (max === 1) {
33
+ x = v0
34
+ y = dropped
35
+ z = v1
36
+ w = v2
37
+ } else if (max === 2) {
38
+ x = v0
39
+ y = v1
40
+ z = dropped
41
+ w = v2
42
+ } else {
43
+ x = v0
44
+ y = v1
45
+ z = v2
46
+ w = dropped
47
+ }
48
+
49
+ output[output_offset] = x;
50
+ output[output_offset + 1] = y;
51
+ output[output_offset + 2] = z;
52
+ output[output_offset + 3] = w;
53
+ }
@@ -0,0 +1,105 @@
1
+ import { assert } from "../../../assert.js";
2
+
3
+ /**
4
+ * Based on GDC talk from Bungie on destiny, compressing quaternions for animation
5
+ * @param {number} x
6
+ * @param {number} y
7
+ * @param {number} z
8
+ * @param {number} w
9
+ * @returns {number}
10
+ */
11
+ export function quat_encode_to_uint32(x, y, z, w) {
12
+
13
+ const absX = Math.abs(x);
14
+ const absY = Math.abs(y);
15
+ const absZ = Math.abs(z);
16
+ const absW = Math.abs(w);
17
+
18
+ let v0, v1, v2, dropped, max;
19
+
20
+ //pick max component
21
+ if (absY > absX) {
22
+ if (absY > absZ) {
23
+ if (absY > absW) {
24
+ //absY is max
25
+ max = 1;
26
+ } else {
27
+ //absW is max
28
+ max = 3;
29
+ }
30
+ } else if (absZ > absW) {
31
+ //absZ is max
32
+ max = 2;
33
+ } else {
34
+ //absW is max
35
+ max = 3;
36
+ }
37
+ } else if (absX > absZ) {
38
+ if (absX > absW) {
39
+ max = 0;
40
+ } else {
41
+ max = 3;
42
+ }
43
+ } else if (absZ > absW) {
44
+ max = 2;
45
+ } else {
46
+ max = 3;
47
+ }
48
+
49
+
50
+ //max will be dropped
51
+ if (max === 0) {
52
+ //dropping x
53
+ v0 = y;
54
+ v1 = z;
55
+ v2 = w;
56
+
57
+ dropped = x;
58
+ } else if (max === 1) {
59
+ //dropping y
60
+ v0 = x;
61
+ v1 = z;
62
+ v2 = w;
63
+
64
+ dropped = y;
65
+ } else if (max === 2) {
66
+ //dropping z
67
+ v0 = x;
68
+ v1 = y;
69
+ v2 = w;
70
+
71
+ dropped = z;
72
+ } else {
73
+ //dropping w
74
+ v0 = x;
75
+ v1 = y;
76
+ v2 = z;
77
+
78
+ dropped = w;
79
+ }
80
+
81
+ if (dropped < 0) {
82
+ //reconstructing dropped value is only possible if it is positive, so we invert the quaternion to make dropped value positive
83
+ v0 = -v0;
84
+ v1 = -v1;
85
+ v2 = -v2;
86
+ }
87
+
88
+ const l = Math.hypot(v0, v1, v2, dropped);
89
+ const m = 511 / (l * Math.SQRT1_2);
90
+
91
+ //re-normalize the remaining components to 10 bit UINT value
92
+ const oV0 = Math.round(v0 * m + 511);
93
+ const oV1 = Math.round(v1 * m + 511);
94
+ const oV2 = Math.round(v2 * m + 511);
95
+
96
+ assert.ok(oV0 <= 1023 && oV0 >= 0, `expected 0 <= ov0 <= 1023, instead was '${oV0}'`);
97
+ assert.ok(oV1 <= 1023 && oV1 >= 0, `expected 0 <= ov1 <= 1023, instead was '${oV1}'`);
98
+ assert.ok(oV2 <= 1023 && oV2 >= 0, `expected 0 <= ov2 <= 1023, instead was '${oV2}'`);
99
+
100
+
101
+ return (max & 0x3)
102
+ | ((oV0 & 0x3FF) << 2)
103
+ | ((oV1 & 0x3FF) << 12)
104
+ | ((oV2 & 0x3FF) << 22);
105
+ }
@@ -6,31 +6,21 @@
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 { EPSILON } from "../math/EPSILON.js";
10
+ import { epsilonEquals } from "../math/epsilonEquals.js";
9
11
  import { lerp } from "../math/lerp.js";
10
- import Vector3 from "./Vector3.js";
11
- import { v3_dot } from "./vec3/v3_dot.js";
12
12
  import { min2 } from "../math/min2.js";
13
13
  import { computeHashFloat } from "../primitives/numbers/computeHashFloat.js";
14
- import { epsilonEquals } from "../math/epsilonEquals.js";
15
- import { EPSILON } from "../math/EPSILON.js";
14
+ import { quat_decode_from_uint32 } from "./3d/quaternion/quat_decode_from_uint32.js";
15
+ import { quat_encode_to_uint32 } from "./3d/quaternion/quat_encode_to_uint32.js";
16
+ import { v3_dot } from "./vec3/v3_dot.js";
17
+ import Vector3 from "./Vector3.js";
16
18
 
17
19
 
18
20
  const forward = new Vector3();
19
21
  const up = new Vector3();
20
22
  const right = new Vector3();
21
23
 
22
- /**
23
- * just in case you need that function also
24
- * @param {Vector3} axis
25
- * @param {number} angle
26
- * @param {Quaternion} result
27
- */
28
- export function quat3_createFromAxisAngle(axis, angle, result) {
29
- const halfAngle = angle * .5;
30
- const s = Math.sin(halfAngle);
31
- result.set(axis.x * s, axis.y * s, axis.z * s, Math.cos(halfAngle));
32
- }
33
-
34
24
  class Quaternion {
35
25
  /**
36
26
  *
@@ -1453,31 +1443,7 @@ class Quaternion {
1453
1443
  * @param {number} value
1454
1444
  */
1455
1445
  decodeFromUint32(value) {
1456
- //read components
1457
- const max = value & 0x3;
1458
-
1459
- const iv0 = (value >> 2) & 0x3FF;
1460
- const iv1 = (value >> 12) & 0x3FF;
1461
- const iv2 = (value >> 22) & 0x3FF;
1462
-
1463
- //scale components back to quaternion range
1464
- const v0 = (iv0 / 511 - 1) * K_CONST;
1465
- const v1 = (iv1 / 511 - 1) * K_CONST;
1466
- const v2 = (iv2 / 511 - 1) * K_CONST;
1467
-
1468
- //restore dropped component using quaternion identity: x^2 + y^2 + z^2 + w^2 = 1
1469
- const dropped_2 = 1 - v0 * v0 - v1 * v1 - v2 * v2;
1470
- const dropped = Math.sqrt(dropped_2);
1471
-
1472
- if (max === 0) {
1473
- this.set(dropped, v0, v1, v2);
1474
- } else if (max === 1) {
1475
- this.set(v0, dropped, v1, v2);
1476
- } else if (max === 2) {
1477
- this.set(v0, v1, dropped, v2);
1478
- } else {
1479
- this.set(v0, v1, v2, dropped);
1480
- }
1446
+ quat_decode_from_uint32(this, 0, value);
1481
1447
  }
1482
1448
 
1483
1449
  /**
@@ -1485,107 +1451,7 @@ class Quaternion {
1485
1451
  * @returns {number}
1486
1452
  */
1487
1453
  encodeToUint32() {
1488
- const x = this.x;
1489
- const y = this.y;
1490
- const z = this.z;
1491
- const w = this.w;
1492
-
1493
- const absX = Math.abs(x);
1494
- const absY = Math.abs(y);
1495
- const absZ = Math.abs(z);
1496
- const absW = Math.abs(w);
1497
-
1498
- let max = 0;
1499
-
1500
- //pick max component
1501
- if (absY > absX) {
1502
- if (absY > absZ) {
1503
- if (absY > absW) {
1504
- //absY is max
1505
- max = 1;
1506
- } else {
1507
- //absW is max
1508
- max = 3;
1509
- }
1510
- } else if (absZ > absW) {
1511
- //absZ is max
1512
- max = 2;
1513
- } else {
1514
- //absW is max
1515
- max = 3;
1516
- }
1517
- } else if (absX > absZ) {
1518
- if (absX > absW) {
1519
- max = 0;
1520
- } else {
1521
- max = 3;
1522
- }
1523
- } else if (absZ > absW) {
1524
- max = 2;
1525
- } else {
1526
- max = 3;
1527
- }
1528
-
1529
- let v0, v1, v2, dropped;
1530
-
1531
- //max will be dropped
1532
- if (max === 0) {
1533
- //dropping x
1534
- v0 = y;
1535
- v1 = z;
1536
- v2 = w;
1537
-
1538
- dropped = x;
1539
- } else if (max === 1) {
1540
- //dropping y
1541
- v0 = x;
1542
- v1 = z;
1543
- v2 = w;
1544
-
1545
- dropped = y;
1546
- } else if (max === 2) {
1547
- //dropping z
1548
- v0 = x;
1549
- v1 = y;
1550
- v2 = w;
1551
-
1552
- dropped = z;
1553
- } else {
1554
- //dropping w
1555
- v0 = x;
1556
- v1 = y;
1557
- v2 = z;
1558
-
1559
- dropped = w;
1560
- }
1561
-
1562
- if (dropped < 0) {
1563
- //reconstructing dropped value is only possible if it is positive, so we invert the quaternion to make dropped value positive
1564
- v0 = -v0;
1565
- v1 = -v1;
1566
- v2 = -v2;
1567
- }
1568
-
1569
- const l = Math.sqrt(x * x + y * y + z * z + w * w);
1570
- const m = 1 / (l * K_CONST);
1571
-
1572
- //re-normalize the remaining components to 10 bit UINT value
1573
- const oV0 = Math.round((v0 * m + 1) * 511);
1574
- const oV1 = Math.round((v1 * m + 1) * 511);
1575
- const oV2 = Math.round((v2 * m + 1) * 511);
1576
-
1577
- assert.ok(oV0 <= 1023 && oV0 >= 0, `expected 0 <= ov0 <= 1023, instead was '${oV0}'`);
1578
- assert.ok(oV1 <= 1023 && oV1 >= 0, `expected 0 <= ov1 <= 1023, instead was '${oV1}'`);
1579
- assert.ok(oV2 <= 1023 && oV2 >= 0, `expected 0 <= ov2 <= 1023, instead was '${oV2}'`);
1580
-
1581
-
1582
- const result = (max & 0x3)
1583
- | ((oV0 & 0x3FF) << 2)
1584
- | ((oV1 & 0x3FF) << 12)
1585
- | ((oV2 & 0x3FF) << 22)
1586
- ;
1587
-
1588
- return result;
1454
+ return quat_encode_to_uint32(this.x, this.y, this.z, this.w);
1589
1455
  }
1590
1456
 
1591
1457
  /**