@woosh/meep-engine 2.34.49 → 2.35.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 (51) hide show
  1. package/core/bvh2/BinaryNode.js +19 -35
  2. package/core/bvh2/aabb3/aabb3_intersects_frustum_array.js +5 -5
  3. package/core/bvh2/aabb3_combined_surface_area.js +21 -0
  4. package/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +24 -12
  5. package/core/cache/Cache.d.ts +2 -0
  6. package/core/cache/Cache.js +27 -23
  7. package/core/geom/3d/frustum/frustum_from_projection_matrix_array.js +2 -0
  8. package/core/math/max2.js +2 -6
  9. package/core/math/min2.js +2 -6
  10. package/engine/asset/loaders/geometry/geometry/computeGeometryEquality.js +1 -1
  11. package/engine/asset/loaders/geometry/geometry/computeGeometryHash.js +9 -1
  12. package/engine/ecs/EntityComponentDataset.js +7 -2
  13. package/engine/ecs/foliage/ViewState.js +13 -3
  14. package/engine/ecs/parent/EntityNode.js +23 -11
  15. package/engine/ecs/transform/Transform.js +15 -13
  16. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +63 -26
  17. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +63 -3
  18. package/engine/graphics/ecs/mesh-v2/render/AbstractRenderAdapter.js +67 -0
  19. package/engine/graphics/ecs/mesh-v2/render/GenericRendererAdapter.js +48 -0
  20. package/engine/graphics/ecs/mesh-v2/render/InstancedRendererAdapter.js +110 -0
  21. package/engine/graphics/ecs/mesh-v2/render/ShadedGeometryRendererContext.js +98 -0
  22. package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +5 -0
  23. package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +23 -5
  24. package/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +8 -3
  25. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +23 -85
  26. package/engine/graphics/geometry/instancing/rewriteMaterial.js +9 -45
  27. package/engine/graphics/material/optimization/BUFFER_GEOMETRY_UVS.js +10 -0
  28. package/engine/graphics/material/optimization/MaterialDescriptor.js +46 -0
  29. package/engine/graphics/material/optimization/MaterialOptimizationContext.js +470 -201
  30. package/engine/graphics/material/optimization/UvContext.js +18 -0
  31. package/engine/graphics/material/optimization/is_compliant_mesh.js +71 -0
  32. package/engine/graphics/material/optimization/prepare_atlas_texture.js +23 -0
  33. package/engine/graphics/material/optimization/prototypeMaterialOptimizer.js +127 -0
  34. package/engine/graphics/micron/format/MicronGeometryPatch.js +1 -1
  35. package/engine/graphics/micron/format/VirtualGeometry.js +47 -11
  36. package/engine/graphics/micron/format/serialization/MicronGeometryBinarySerializationAdapter.js +16 -0
  37. package/engine/graphics/micron/prototypeVirtualGeometry.js +3 -2
  38. package/engine/graphics/micron/render/VirtualGeometryBuilder.js +5 -7
  39. package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +1 -45
  40. package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +18 -7
  41. package/engine/graphics/micron/render/refinement/RefinementSpec.js +0 -1
  42. package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +17 -24
  43. package/engine/graphics/micron/render/v1/MaterialContext.js +3 -2
  44. package/engine/graphics/micron/render/v1/VGThreeRenderer.js +19 -4
  45. package/engine/graphics/render/utils/ThreeBypassRenderer.js +3 -2
  46. package/engine/graphics/texture/normalized_internal_format.js +48 -0
  47. package/engine/graphics/texture/sampler/Sampler2D.js +6 -0
  48. package/engine/graphics/texture/sampler/sampler2d_copy_channel_data.js +25 -0
  49. package/engine/graphics/texture/sampler/scaleSampler2D.js +3 -0
  50. package/engine/graphics/texture/sampler/util/drawSamplerHTML.js +14 -1
  51. package/package.json +1 -1
@@ -15,7 +15,7 @@ import { BVHVisitor } from "./traversal/BVHVisitor.js";
15
15
  import { traverseBinaryNodeUsingVisitor } from "./traversal/traverseBinaryNodeUsingVisitor.js";
16
16
  import { aabb3_intersect_aabb3 } from "./aabb3/aabb3_intersect_aabb3.js";
17
17
  import { aabb3_box_surface_area_2 } from "./aabb3/aabb3_box_surface_area_2.js";
18
- import { aabb3_compute_half_surface_area } from "./aabb3/aabb3_compute_half_surface_area.js";
18
+ import { aabb3_combined_surface_area } from "./aabb3_combined_surface_area.js";
19
19
 
20
20
 
21
21
  /**
@@ -206,6 +206,7 @@ export class BinaryNode extends Node {
206
206
  /**
207
207
  * For incremental insertion, a sibling needs to be found, newly inserted node will be parented together with this sibling
208
208
  * @see https://github.com/erincatto/box2d/blob/9dc24a6fd4f32442c4bcf80791de47a0a7d25afb/src/collision/b2_dynamic_tree.cpp#L197
209
+ * @private
209
210
  * @param {AABB3} box
210
211
  * @returns {BinaryNode|LeafNode}
211
212
  */
@@ -215,13 +216,13 @@ export class BinaryNode extends Node {
215
216
  let cost_left = 0;
216
217
  let cost_right = 0;
217
218
 
218
- while (node.isBinaryNode) {
219
+ while (node.isBinaryNode === true) {
219
220
  const left = node.left;
220
221
  const right = node.right;
221
222
 
222
223
  const area = aabb3_box_surface_area_2(node);
223
224
 
224
- const combined_area = combined_surface_area(node, box);
225
+ const combined_area = aabb3_combined_surface_area(node, box);
225
226
 
226
227
  //cost of creating a new parent for this node and the new leaf
227
228
  const cost = combined_area;
@@ -231,10 +232,11 @@ export class BinaryNode extends Node {
231
232
 
232
233
  // cost of descending left
233
234
  if (left !== null) {
235
+ const combined_left = aabb3_combined_surface_area(left, box);
234
236
  if (left.isLeafNode) {
235
- cost_left = combined_surface_area(left, box) + inheritance_cost;
237
+ cost_left = combined_left + inheritance_cost;
236
238
  } else {
237
- cost_left = combined_surface_area(left, box) - aabb3_box_surface_area_2(left) + inheritance_cost;
239
+ cost_left = combined_left - aabb3_box_surface_area_2(left) + inheritance_cost;
238
240
  }
239
241
  } else {
240
242
  cost_left = Infinity;
@@ -243,10 +245,11 @@ export class BinaryNode extends Node {
243
245
  // cost of descending right
244
246
  if (right !== null) {
245
247
 
248
+ const combined_right = aabb3_combined_surface_area(right, box);
246
249
  if (right.isLeafNode) {
247
- cost_right = combined_surface_area(right, box) + inheritance_cost;
250
+ cost_right = combined_right + inheritance_cost;
248
251
  } else {
249
- cost_right = combined_surface_area(right, box) - aabb3_box_surface_area_2(right) + inheritance_cost;
252
+ cost_right = combined_right - aabb3_box_surface_area_2(right) + inheritance_cost;
250
253
  }
251
254
  } else {
252
255
  cost_right = Infinity;
@@ -1045,10 +1048,9 @@ export class BinaryNode extends Node {
1045
1048
 
1046
1049
  const sibling = this.__insertion_findSiblingFor(child);
1047
1050
 
1048
- const sibling_parent = sibling.parentNode;
1049
- let parent = sibling_parent;
1051
+ let parent = sibling.parentNode;
1050
1052
 
1051
- if (sibling_parent === null) {
1053
+ if (parent === null) {
1052
1054
  // "sibling" is the root node
1053
1055
 
1054
1056
  parent = sibling;
@@ -1069,15 +1071,15 @@ export class BinaryNode extends Node {
1069
1071
 
1070
1072
  // non-root
1071
1073
 
1072
- if (sibling_parent.left === sibling && sibling_parent.right === null) {
1074
+ if (parent.left === sibling && parent.right === null) {
1073
1075
 
1074
1076
  // right node is free, take it
1075
- sibling_parent.setChildRight(child);
1077
+ parent.setChildRight(child);
1076
1078
 
1077
- } else if (sibling_parent.right === sibling && sibling_parent.left === null) {
1079
+ } else if (parent.right === sibling && parent.left === null) {
1078
1080
 
1079
1081
  // left node is free, take it
1080
- sibling_parent.setChildLeft(child);
1082
+ parent.setChildLeft(child);
1081
1083
 
1082
1084
  } else {
1083
1085
 
@@ -1088,7 +1090,7 @@ export class BinaryNode extends Node {
1088
1090
  }
1089
1091
 
1090
1092
  // walk back up the tree fixing heights and bounds
1091
- while (parent !== null) {
1093
+ do {
1092
1094
  // parent = this.balance();
1093
1095
 
1094
1096
  const left = parent.left;
@@ -1098,7 +1100,7 @@ export class BinaryNode extends Node {
1098
1100
  parent.refit();
1099
1101
 
1100
1102
  parent = parent.parentNode;
1101
- }
1103
+ } while (parent !== null);
1102
1104
  }
1103
1105
 
1104
1106
  /**
@@ -1152,25 +1154,7 @@ BinaryNode.prototype.isBinaryNode = true;
1152
1154
  * @returns {number}
1153
1155
  */
1154
1156
  function inclusion_surface_area_heuristic(node, addition) {
1155
- return combined_surface_area(node, addition) - aabb3_box_surface_area_2(node);
1156
- }
1157
-
1158
- /**
1159
- *
1160
- * @param {AABB3} node
1161
- * @param {AABB3} addition
1162
- * @returns {number}
1163
- */
1164
- function combined_surface_area(node, addition) {
1165
- const x0 = min2(node.x0, addition.x0);
1166
- const y0 = min2(node.y0, addition.y0);
1167
- const z0 = min2(node.z0, addition.z0);
1168
-
1169
- const x1 = max2(node.x1, addition.x1);
1170
- const y1 = max2(node.y1, addition.y1);
1171
- const z1 = max2(node.z1, addition.z1);
1172
-
1173
- return aabb3_compute_half_surface_area(x0, y0, z0, x1, y1, z1);
1157
+ return aabb3_combined_surface_area(node, addition) - aabb3_box_surface_area_2(node);
1174
1158
  }
1175
1159
 
1176
1160
  /**
@@ -32,13 +32,13 @@ export function aabb3_intersects_frustum_array(aabb, frustum) {
32
32
  export function aabb3_intersects_frustum(x0, y0, z0, x1, y1, z1, frustum) {
33
33
  for (let i = 0; i < 24; i += 4) {
34
34
 
35
- const plane_n_x = frustum[i];
36
- const plane_n_y = frustum[i + 1];
37
- const plane_n_z = frustum[i + 2];
38
- const plane_constant = frustum[i + 3];
35
+ const plane_x = frustum[i];
36
+ const plane_y = frustum[i + 1];
37
+ const plane_z = frustum[i + 2];
38
+ const plane_w = frustum[i + 3];
39
39
 
40
40
  const plane_distance = aabb3_computeDistanceAbovePlane(
41
- plane_n_x, plane_n_y, plane_n_z, plane_constant,
41
+ plane_x, plane_y, plane_z, plane_w,
42
42
  x0, y0, z0,
43
43
  x1, y1, z1
44
44
  );
@@ -0,0 +1,21 @@
1
+ import { min2 } from "../math/min2.js";
2
+ import { max2 } from "../math/max2.js";
3
+ import { aabb3_compute_half_surface_area } from "./aabb3/aabb3_compute_half_surface_area.js";
4
+
5
+ /**
6
+ *
7
+ * @param {AABB3} a
8
+ * @param {AABB3} b
9
+ * @returns {number}
10
+ */
11
+ export function aabb3_combined_surface_area(a, b) {
12
+ const x0 = min2(a.x0, b.x0);
13
+ const y0 = min2(a.y0, b.y0);
14
+ const z0 = min2(a.z0, b.z0);
15
+
16
+ const x1 = max2(a.x1, b.x1);
17
+ const y1 = max2(a.y1, b.y1);
18
+ const z1 = max2(a.z1, b.z1);
19
+
20
+ return aabb3_compute_half_surface_area(x0, y0, z0, x1, y1, z1);
21
+ }
@@ -8,45 +8,57 @@ const stack = [];
8
8
  /**
9
9
  * @template T
10
10
  * @param {T[]} destination
11
- * @param {number} destinationOffset
11
+ * @param {number} destination_offset
12
12
  * @param {BinaryNode<T>} root
13
13
  * @param {ArrayLike<number>|number[]|Float32Array} frustum
14
14
  * @returns {number} Number of results
15
15
  */
16
- export function queryBinaryNode_FrustumIntersections_Data(destination, destinationOffset, root, frustum) {
16
+ export function queryBinaryNode_FrustumIntersections_Data(destination, destination_offset, root, frustum) {
17
+
18
+ /**
19
+ * @type {BinaryNode<T>|LeafNode<T>}
20
+ */
17
21
  let n;
18
- let i = 0;
22
+ let offset = destination_offset;
19
23
  let stackPointer = 1;
20
24
 
21
25
  stack[0] = root;
22
26
 
23
27
  while (stackPointer > 0) {
28
+
24
29
  stackPointer--;
25
30
 
26
31
  n = stack[stackPointer];
27
32
 
28
- if (!n.intersectFrustum_array(frustum)) {
33
+ const node_intersects_frustum = n.intersectFrustum_array(frustum);
34
+
35
+ if (!node_intersects_frustum) {
29
36
  continue;
30
37
  }
31
38
 
32
- if (n.isBinaryNode) {
39
+ if (n.isBinaryNode === true) {
33
40
 
34
- if (n.right !== null) {
35
- stack[stackPointer++] = n.right;
41
+ const right = n.right;
42
+
43
+ if (right !== null) {
44
+ stack[stackPointer++] = right;
36
45
  }
37
46
 
38
- if (n.left !== null) {
39
- stack[stackPointer++] = n.left;
47
+ const left = n.left;
48
+
49
+ if (left !== null) {
50
+ stack[stackPointer++] = left;
40
51
  }
41
52
 
42
53
  } else {
54
+ // leaf node
43
55
 
44
- destination[destinationOffset + i] = n.object;
56
+ destination[offset] = n.object;
45
57
 
46
- i++;
58
+ offset++;
47
59
  }
48
60
 
49
61
  }
50
62
 
51
- return i;
63
+ return offset - destination_offset;
52
64
  }
@@ -28,4 +28,6 @@ export class Cache<K, V> {
28
28
  clear(): void
29
29
 
30
30
  drop(): void
31
+
32
+ getOrCompute(key: K, compute: (key: K) => V, compute_context?: any): V
31
33
  }
@@ -1,7 +1,7 @@
1
1
  import { assert } from "../assert.js";
2
2
  import { HashMap } from "../collection/HashMap.js";
3
3
  import Signal from "../events/signal/Signal.js";
4
- import { noop, returnOne, returnZero, strictEquals } from "../function/Functions.js";
4
+ import { returnOne, returnZero, strictEquals } from "../function/Functions.js";
5
5
  import { CacheElement } from "./CacheElement.js";
6
6
 
7
7
  /**
@@ -14,33 +14,25 @@ export class Cache {
14
14
  * @param {number} [maxWeight=Number.POSITIVE_INFINITY]
15
15
  * @param {function(key:Key):number} [keyWeigher= key=>0]
16
16
  * @param {function(value:Value):number} [valueWeigher= value=>1]
17
- * @param {function(key:Key, value:Value)} [removeListener] will be notified when element is either explicitly removed or evicted
18
17
  * @param {function(Key):number} [keyHashFunction]
19
18
  * @param {function(Key, Key):boolean} [keyEqualityFunction]
20
19
  * @param {number} capacity initial capacity for the cache, helps prevent early resizing
21
20
  * @constructor
22
- * @template Key, Value
23
21
  */
24
22
  constructor({
25
23
  maxWeight = Number.POSITIVE_INFINITY,
26
24
  keyWeigher = returnZero,
27
25
  valueWeigher = returnOne,
28
- removeListener = noop,
29
26
  keyHashFunction = returnZero,
30
27
  keyEqualityFunction = strictEquals,
31
28
  capacity
32
29
  } = {}) {
33
30
 
34
31
  assert.isNumber(maxWeight, 'maxWeight');
35
- assert.typeOf(keyWeigher, 'function', 'keyWeigher');
36
- assert.typeOf(valueWeigher, 'function', 'valueWeigher');
37
- assert.typeOf(removeListener, 'function', 'removeListener');
38
- assert.typeOf(keyHashFunction, 'function', 'keyHashFunction');
39
- assert.typeOf(keyEqualityFunction, 'function', 'keyEqualityFunction');
40
-
41
- if (removeListener !== noop) {
42
- console.warn('removalListener is deprecated, use onRemoved signal instead');
43
- }
32
+ assert.isFunction(keyWeigher, 'keyWeigher');
33
+ assert.isFunction(valueWeigher, 'valueWeigher');
34
+ assert.isFunction(keyHashFunction, 'keyHashFunction');
35
+ assert.isFunction(keyEqualityFunction, 'keyEqualityFunction');
44
36
 
45
37
  /**
46
38
  *
@@ -70,13 +62,6 @@ export class Cache {
70
62
  */
71
63
  this.valueWeigher = valueWeigher;
72
64
 
73
- /**
74
- *
75
- * @type {function(Key, Value)}
76
- * @private
77
- */
78
- this.removeListener = removeListener;
79
-
80
65
  /**
81
66
  *
82
67
  * @type {CacheElement<Key,Value>|null}
@@ -93,7 +78,7 @@ export class Cache {
93
78
 
94
79
  /**
95
80
  *
96
- * @type {HashMap<Key, CacheElement<Key,Value>t>}
81
+ * @type {HashMap<Key, CacheElement<Key,Value>>}
97
82
  * @private
98
83
  */
99
84
  this.data = new HashMap({
@@ -398,13 +383,32 @@ export class Cache {
398
383
  this.__removeElement(element);
399
384
 
400
385
  //notify
401
- this.removeListener(key, element.value);
402
-
403
386
  this.onRemoved.send2(key, element.value);
404
387
 
405
388
  return true;
406
389
  }
407
390
 
391
+ /**
392
+ *
393
+ * @param {Key} key
394
+ * @param {function(Key):Value} compute
395
+ * @param {*} [compute_context]
396
+ * @return {Value}
397
+ */
398
+ getOrCompute(key, compute, compute_context) {
399
+ const existing = this.get(key);
400
+
401
+ if (existing !== null) {
402
+ return existing;
403
+ }
404
+
405
+ const value = compute.call(compute_context, key);
406
+
407
+ this.set(key, value);
408
+
409
+ return value;
410
+ }
411
+
408
412
  /**
409
413
  * Remove all elements from the cache
410
414
  */
@@ -25,6 +25,8 @@ function array_set_plane_normalized(
25
25
 
26
26
  /**
27
27
  * Set frustum from projection matrix
28
+ * NOTE: uses Gribb/Hartmann method
29
+ * @see "Fast Extraction of Viewing Frustum Planes from the WorldView-Projection Matrix", 2001 by Gribb & Hartmann
28
30
  * @param {number[]|Float32Array} frustum_planes
29
31
  * @param {number[]} m4
30
32
  */
package/core/math/max2.js CHANGED
@@ -6,9 +6,5 @@
6
6
  * @returns {number}
7
7
  */
8
8
  export function max2(a, b) {
9
- if (a < b) {
10
- return b;
11
- } else {
12
- return a;
13
- }
14
- }
9
+ return a < b ? b : a;
10
+ }
package/core/math/min2.js CHANGED
@@ -5,9 +5,5 @@
5
5
  * @returns {number}
6
6
  */
7
7
  export function min2(a, b) {
8
- if (a < b) {
9
- return a;
10
- } else {
11
- return b;
12
- }
13
- }
8
+ return a < b ? a : b;
9
+ }
@@ -18,7 +18,7 @@ export function computeGeometryEquality(a, b) {
18
18
  return false;
19
19
  }
20
20
 
21
- if (!isArrayEqualStrict(a_index.array, b_index.array)) {
21
+ if (!is_typed_array_equals(a_index.array, b_index.array)) {
22
22
  return false;
23
23
  }
24
24
  }
@@ -1,4 +1,5 @@
1
1
  import { computeBufferAttributeHash } from "./computeBufferAttributeHash.js";
2
+ import { computeStringHash } from "../../../../../core/primitives/strings/computeStringHash.js";
2
3
 
3
4
  /**
4
5
  *
@@ -6,7 +7,14 @@ import { computeBufferAttributeHash } from "./computeBufferAttributeHash.js";
6
7
  * @returns {number}
7
8
  */
8
9
  export function computeGeometryHash(geometry) {
9
- let hash = computeBufferAttributeHash(geometry.getIndex());
10
+ let hash = 0;
11
+ const attributes = geometry.attributes;
12
+
13
+ for (const attributesKey in attributes) {
14
+ hash = hash * 31 + computeStringHash(attributesKey);
15
+ }
16
+
17
+ hash ^= computeBufferAttributeHash(geometry.getIndex());
10
18
 
11
19
  const position_attribute = geometry.getAttribute('position');
12
20
 
@@ -1319,11 +1319,16 @@ export class EntityComponentDataset {
1319
1319
 
1320
1320
  const numObservers = observersStore.length;
1321
1321
 
1322
- let i;
1322
+ if (numObservers === 0) {
1323
+ // no observers
1324
+ return;
1325
+ }
1326
+
1327
+ let i = 0;
1323
1328
 
1324
1329
  const args = [];
1325
1330
 
1326
- for (i = 0; i < numObservers; i++) {
1331
+ for (; i < numObservers; i++) {
1327
1332
  const observer = observersStore[i];
1328
1333
 
1329
1334
  const match = matchComponentMask(this.componentOccupancy, entityIndex, this.componentTypeCount, observer.componentMask);
@@ -2,6 +2,8 @@ import { BitSet } from "../../../core/binary/BitSet.js";
2
2
  import { InstancedMeshGroup } from "../../graphics/geometry/instancing/InstancedMeshGroup.js";
3
3
  import { queryBinaryNode_FrustumIntersections_Data } from "../../../core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js";
4
4
  import Quaternion from "../../../core/geom/Quaternion.js";
5
+ import { compose_matrix4_array } from "../../graphics/util/composeMatrix4.js";
6
+ import Vector3 from "../../../core/geom/Vector3.js";
5
7
 
6
8
  /**
7
9
  *
@@ -153,13 +155,21 @@ export class ViewState {
153
155
 
154
156
  tempQuaternion.decodeFromUint32(encodedRotation);
155
157
 
158
+ scratch_v3_0.set(positionX, positionY, positionZ);
159
+ scratch_v3_1.set(scaleX, scaleY, scaleZ);
160
+
161
+ // compose transform
162
+ compose_matrix4_array(scratch_transform, scratch_v3_0, tempQuaternion, scratch_v3_1);
163
+
156
164
  //apply instance transforms
157
- instances.setPositionAt(i, positionX, positionY, positionZ);
158
- instances.setRotationAt(i, tempQuaternion.x, tempQuaternion.y, tempQuaternion.z, tempQuaternion.w);
159
- instances.setScaleAt(i, scaleX, scaleY, scaleZ);
165
+ instances.setTransformAt(i, scratch_transform);
166
+ instances.requestAttributeUpdate();
160
167
  }
161
168
  }
162
169
  }
163
170
 
164
171
  const tempQuaternion = new Quaternion();
172
+ const scratch_v3_0 = new Vector3();
173
+ const scratch_v3_1 = new Vector3();
165
174
  const rowData = [];
175
+ const scratch_transform = new Float32Array(16);
@@ -4,7 +4,7 @@ import { array_remove_first } from "../../../core/collection/array/array_remove_
4
4
  import { assert } from "../../../core/assert.js";
5
5
  import { array_push_if_unique } from "../../../core/collection/array/array_push_if_unique.js";
6
6
  import { Transform } from "../transform/Transform.js";
7
- import { TransformAttachment } from "../transform-attachment/TransformAttachment.js";
7
+ import { TransformAttachment, TransformAttachmentFlags } from "../transform-attachment/TransformAttachment.js";
8
8
 
9
9
  export class EntityNode {
10
10
  /**
@@ -18,12 +18,14 @@ export class EntityNode {
18
18
  * @private
19
19
  */
20
20
  this.__parent = null;
21
+
21
22
  /**
22
23
  *
23
24
  * @type {EntityBuilder}
24
25
  * @private
25
26
  */
26
27
  this.__entity = entity;
28
+
27
29
  /**
28
30
  *
29
31
  * @type {EntityNode[]}
@@ -32,7 +34,7 @@ export class EntityNode {
32
34
  this.__children = [];
33
35
 
34
36
  /**
35
- *
37
+ * Local transform
36
38
  * @type {Transform}
37
39
  * @private
38
40
  */
@@ -45,13 +47,18 @@ export class EntityNode {
45
47
  */
46
48
  __transform_sync_down() {
47
49
 
50
+ const transform = this.__transform;
51
+
48
52
  if (this.__parent === null) {
49
- const t = this.__entity.getComponent(Transform);
50
- if (t !== null) {
51
- t.copy(this.__transform);
53
+ // not attached to anything, world and local transforms match
54
+ const cTransform = this.__entity.getComponent(Transform);
55
+
56
+ if (cTransform !== null) {
57
+ cTransform.copy(transform);
52
58
  }
59
+
53
60
  } else {
54
- this.__safe_get_attachment().transform.copy(this.__transform);
61
+ this.__safe_get_attachment().transform.copy(transform);
55
62
  }
56
63
 
57
64
  }
@@ -85,7 +92,7 @@ export class EntityNode {
85
92
 
86
93
  if (attachment === null) {
87
94
  attachment = new TransformAttachment();
88
- attachment.immediate = true;
95
+ attachment.setFlag(TransformAttachmentFlags.Immediate);
89
96
 
90
97
  entity.add(attachment);
91
98
  }
@@ -115,13 +122,15 @@ export class EntityNode {
115
122
  set parent(node) {
116
123
  this.__parent = node;
117
124
 
125
+ const this_entity = this.__entity;
126
+
118
127
  // check if entity is built
119
- if (!this.__entity.isBuilt) {
128
+ if (!this_entity.isBuilt) {
120
129
  return;
121
130
  }
122
131
 
123
- let parent_entity = this.__entity.removeComponent(ParentEntity);
124
- let attachment = this.__entity.removeComponent(TransformAttachment);
132
+ let parent_entity = this_entity.removeComponent(ParentEntity);
133
+ let attachment = this_entity.removeComponent(TransformAttachment);
125
134
 
126
135
  if (node !== null) {
127
136
 
@@ -141,7 +150,7 @@ export class EntityNode {
141
150
  parent_entity.entity = parent_entity_id;
142
151
 
143
152
  // add component back
144
- this.__entity.add(parent_entity);
153
+ this_entity.add(parent_entity);
145
154
 
146
155
 
147
156
  // handle component Attachment
@@ -230,6 +239,8 @@ export class EntityNode {
230
239
  }
231
240
 
232
241
  this.__transform_sync_down();
242
+
243
+ // attach listeners
233
244
  this.__transform.position.onChanged.add(this.__transform_sync_down, this);
234
245
  this.__transform.scale.onChanged.add(this.__transform_sync_down, this);
235
246
  this.__transform.rotation.onChanged.add(this.__transform_sync_down, this);
@@ -247,6 +258,7 @@ export class EntityNode {
247
258
  }
248
259
 
249
260
  destroy() {
261
+ // remove listeners
250
262
  this.__transform.position.onChanged.remove(this.__transform_sync_down, this);
251
263
  this.__transform.scale.onChanged.remove(this.__transform_sync_down, this);
252
264
  this.__transform.rotation.onChanged.remove(this.__transform_sync_down, this);
@@ -4,14 +4,16 @@
4
4
 
5
5
  import Vector3 from "../../../core/geom/Vector3.js";
6
6
  import Quaternion from "../../../core/geom/Quaternion.js";
7
- import { Matrix4 } from "../../../core/geom/Matrix4.js";
8
7
  import { compose_matrix4_array } from "../../graphics/util/composeMatrix4.js";
9
8
  import { decompose_matrix_4_array } from "../../graphics/util/decompose_matrix_4_array.js";
9
+ import { mat4 } from "gl-matrix";
10
10
 
11
11
  const delta = new Vector3();
12
12
 
13
- const m4_0 = new Matrix4();
14
- const m4_1 = new Matrix4();
13
+ const scratch_buffer = new ArrayBuffer(32 * 4);
14
+
15
+ const m4_0 = new Float32Array(scratch_buffer, 0, 16);
16
+ const m4_1 = new Float32Array(scratch_buffer, 64, 16)
15
17
 
16
18
  export class Transform {
17
19
  /**
@@ -152,12 +154,12 @@ export class Transform {
152
154
  * @param {Transform} b
153
155
  */
154
156
  multiplyTransforms(a, b) {
155
- m4_0.compose(a.position, a.rotation, a.scale);
156
- m4_1.compose(b.position, b.rotation, b.scale);
157
+ compose_matrix4_array(m4_0, a.position, a.rotation, a.scale);
158
+ compose_matrix4_array(m4_1, b.position, b.rotation, b.scale);
157
159
 
158
- m4_0.multiplyMatrices(m4_0, m4_1);
160
+ mat4.multiply(m4_0, m4_0, m4_1);
159
161
 
160
- m4_0.decompose(this.position, this.rotation, this.scale);
162
+ this.fromMatrix4(m4_0);
161
163
  }
162
164
 
163
165
  /**
@@ -170,18 +172,18 @@ export class Transform {
170
172
 
171
173
  /**
172
174
  *
173
- * @param {mat4|number[]|Float32Array} m
175
+ * @param {Matrix4} matrix
174
176
  */
175
- fromMatrix4(m) {
176
- decompose_matrix_4_array(m, this.position, this.rotation, this.scale);
177
+ toThreeMatrix(matrix) {
178
+ this.toMatrix4(matrix.elements);
177
179
  }
178
180
 
179
181
  /**
180
182
  *
181
- * @param {Matrix4} matrix
183
+ * @param {mat4|number[]|Float32Array} m
182
184
  */
183
- toThreeMatrix(matrix) {
184
- this.toMatrix4(matrix.elements);
185
+ fromMatrix4(m) {
186
+ decompose_matrix_4_array(m, this.position, this.rotation, this.scale);
185
187
  }
186
188
 
187
189
  /**