@woosh/meep-engine 2.46.31 → 2.46.34

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/build/meep.cjs CHANGED
@@ -660,7 +660,7 @@ class Signal {
660
660
  * @param {*} [context]
661
661
  */
662
662
  addOne(h, context) {
663
- assert.equal(typeof h, "function", "Handler is not a function");
663
+ assert.isFunction( h, "handler");
664
664
 
665
665
  const handler = new SignalHandler(h, context);
666
666
 
@@ -708,8 +708,8 @@ class Signal {
708
708
  * Remove all handlers
709
709
  */
710
710
  removeAll() {
711
- const signalHandlers = this.handlers;
712
- signalHandlers.splice(0, signalHandlers.length);
711
+ const handlers = this.handlers;
712
+ handlers.splice(0, handlers.length);
713
713
  }
714
714
 
715
715
  /**
@@ -49814,7 +49814,7 @@ function arraySwapElements(array, index0, index1) {
49814
49814
  array[index1] = t;
49815
49815
  }
49816
49816
 
49817
- const stack$9 = [];
49817
+ const stack$8 = [];
49818
49818
 
49819
49819
  /**
49820
49820
  * @template T
@@ -49835,14 +49835,14 @@ function arrayQuickSort(data, score_function, score_function_context, start, end
49835
49835
  let stackPointer = 2;
49836
49836
  let i, j;
49837
49837
 
49838
- stack$9[0] = start;
49839
- stack$9[1] = end;
49838
+ stack$8[0] = start;
49839
+ stack$8[1] = end;
49840
49840
 
49841
49841
  while (stackPointer > 0) {
49842
49842
  stackPointer -= 2;
49843
49843
 
49844
- const right = stack$9[stackPointer + 1];
49845
- const left = stack$9[stackPointer];
49844
+ const right = stack$8[stackPointer + 1];
49845
+ const left = stack$8[stackPointer];
49846
49846
 
49847
49847
  i = left;
49848
49848
  j = right;
@@ -49875,12 +49875,12 @@ function arrayQuickSort(data, score_function, score_function_context, start, end
49875
49875
 
49876
49876
  /* recursion */
49877
49877
  if (left < j) {
49878
- stack$9[stackPointer++] = left;
49879
- stack$9[stackPointer++] = j;
49878
+ stack$8[stackPointer++] = left;
49879
+ stack$8[stackPointer++] = j;
49880
49880
  }
49881
49881
  if (i < right) {
49882
- stack$9[stackPointer++] = i;
49883
- stack$9[stackPointer++] = right;
49882
+ stack$8[stackPointer++] = i;
49883
+ stack$8[stackPointer++] = right;
49884
49884
  }
49885
49885
  }
49886
49886
  }
@@ -49902,14 +49902,14 @@ function array_quick_sort_by_comparator(data, compare_function, compare_function
49902
49902
  let stackPointer = 2;
49903
49903
  let i, j;
49904
49904
 
49905
- stack$9[0] = start;
49906
- stack$9[1] = end;
49905
+ stack$8[0] = start;
49906
+ stack$8[1] = end;
49907
49907
 
49908
49908
  while (stackPointer > 0) {
49909
49909
  stackPointer -= 2;
49910
49910
 
49911
- const right = stack$9[stackPointer + 1];
49912
- const left = stack$9[stackPointer];
49911
+ const right = stack$8[stackPointer + 1];
49912
+ const left = stack$8[stackPointer];
49913
49913
 
49914
49914
  i = left;
49915
49915
  j = right;
@@ -49945,12 +49945,12 @@ function array_quick_sort_by_comparator(data, compare_function, compare_function
49945
49945
 
49946
49946
  /* recursion */
49947
49947
  if (left < j) {
49948
- stack$9[stackPointer++] = left;
49949
- stack$9[stackPointer++] = j;
49948
+ stack$8[stackPointer++] = left;
49949
+ stack$8[stackPointer++] = j;
49950
49950
  }
49951
49951
  if (i < right) {
49952
- stack$9[stackPointer++] = i;
49953
- stack$9[stackPointer++] = right;
49952
+ stack$8[stackPointer++] = i;
49953
+ stack$8[stackPointer++] = right;
49954
49954
  }
49955
49955
  }
49956
49956
  }
@@ -50495,7 +50495,7 @@ function aabb3_intersects_frustum_array(x0, y0, z0, x1, y1, z1, frustum) {
50495
50495
  * NOTE: {@link result} and {@link aabb} must be different objects
50496
50496
  * @param {ArrayLike<number>|number[]|Float32Array} result
50497
50497
  * @param {ArrayLike<number>|number[]|Float32Array} aabb
50498
- * @param {number[]} matrix 4x4 matrix
50498
+ * @param {ArrayLike<number>|number[]|Float32Array} matrix 4x4 matrix
50499
50499
  */
50500
50500
  function aabb3_matrix4_project(result, aabb, matrix) {
50501
50501
  assert.notEqual(result, aabb, 'input and output must not be the same for algorithm to work correctly');
@@ -51782,8 +51782,8 @@ class BVHVisitor {
51782
51782
  }
51783
51783
  }
51784
51784
 
51785
- const stack$8 = [];
51786
- let stackPointer$4 = 0;
51785
+ const stack$7 = [];
51786
+ let stackPointer$3 = 0;
51787
51787
 
51788
51788
  /**
51789
51789
  *
@@ -51793,13 +51793,13 @@ let stackPointer$4 = 0;
51793
51793
  function traverseBinaryNodeUsingVisitor(node, visitor) {
51794
51794
  let n;
51795
51795
 
51796
- const stackOffset = stackPointer$4;
51796
+ const stackOffset = stackPointer$3;
51797
51797
 
51798
- stack$8[stackPointer$4++] = node;
51798
+ stack$7[stackPointer$3++] = node;
51799
51799
 
51800
- while (stackPointer$4-- > stackOffset) {
51800
+ while (stackPointer$3-- > stackOffset) {
51801
51801
 
51802
- n = stack$8[stackPointer$4];
51802
+ n = stack$7[stackPointer$3];
51803
51803
 
51804
51804
  if (n.isBinaryNode) {
51805
51805
  const traverseDeeper = visitor.visitBinary(n);
@@ -51810,7 +51810,7 @@ function traverseBinaryNodeUsingVisitor(node, visitor) {
51810
51810
 
51811
51811
  // has a LEFT child
51812
51812
 
51813
- stack$8[stackPointer$4++] = n.left;
51813
+ stack$7[stackPointer$3++] = n.left;
51814
51814
 
51815
51815
  }
51816
51816
 
@@ -51818,7 +51818,7 @@ function traverseBinaryNodeUsingVisitor(node, visitor) {
51818
51818
 
51819
51819
  // has a RIGHT child
51820
51820
 
51821
- stack$8[stackPointer$4++] = n.right;
51821
+ stack$7[stackPointer$3++] = n.right;
51822
51822
 
51823
51823
  }
51824
51824
 
@@ -51830,7 +51830,7 @@ function traverseBinaryNodeUsingVisitor(node, visitor) {
51830
51830
  }
51831
51831
 
51832
51832
  //drop the stack frame
51833
- stackPointer$4 = stackOffset;
51833
+ stackPointer$3 = stackOffset;
51834
51834
  }
51835
51835
 
51836
51836
  /**
@@ -51938,12 +51938,12 @@ function aabb3_combined_surface_area(a, b) {
51938
51938
  *
51939
51939
  * @type {number}
51940
51940
  */
51941
- let stackPointer$3 = 0;
51941
+ let stackPointer$2 = 0;
51942
51942
  /**
51943
51943
  *
51944
51944
  * @type {Node[]}
51945
51945
  */
51946
- const stack$7 = [];
51946
+ const stack$6 = [];
51947
51947
 
51948
51948
  class BinaryNode extends Node {
51949
51949
  constructor() {
@@ -51991,30 +51991,30 @@ class BinaryNode extends Node {
51991
51991
  traversePreOrderUsingStack(visitor, thisArg) {
51992
51992
  let visitCount = 0;
51993
51993
 
51994
- const stackOffset = stackPointer$3;
51994
+ const stackOffset = stackPointer$2;
51995
51995
 
51996
- stack$7[stackPointer$3++] = this;
51996
+ stack$6[stackPointer$2++] = this;
51997
51997
  let n;
51998
- while (stackPointer$3-- > stackOffset) {
51998
+ while (stackPointer$2-- > stackOffset) {
51999
51999
 
52000
52000
  visitCount++;
52001
52001
 
52002
- n = stack$7[stackPointer$3];
52002
+ n = stack$6[stackPointer$2];
52003
52003
 
52004
52004
  const traverseDeeper = visitor.call(thisArg, n);
52005
52005
 
52006
52006
  if (traverseDeeper !== false && n.isBinaryNode) {
52007
52007
  if (n.right !== null) {
52008
- stack$7[stackPointer$3++] = n.right;
52008
+ stack$6[stackPointer$2++] = n.right;
52009
52009
  }
52010
52010
  if (n.left !== null) {
52011
- stack$7[stackPointer$3++] = n.left;
52011
+ stack$6[stackPointer$2++] = n.left;
52012
52012
  }
52013
52013
  }
52014
52014
  }
52015
52015
 
52016
52016
  // drop stack frame
52017
- stackPointer$3 = stackOffset;
52017
+ stackPointer$2 = stackOffset;
52018
52018
 
52019
52019
  return visitCount;
52020
52020
  }
@@ -52027,33 +52027,33 @@ class BinaryNode extends Node {
52027
52027
  traverseLeavesPreOrderUsingStack(visitor, thisArg) {
52028
52028
  let visitCount = 0;
52029
52029
 
52030
- const stackOffset = stackPointer$3;
52030
+ const stackOffset = stackPointer$2;
52031
52031
 
52032
- stack$7[stackPointer$3++] = this;
52032
+ stack$6[stackPointer$2++] = this;
52033
52033
 
52034
52034
  let n;
52035
52035
 
52036
- while (stackPointer$3-- > stackOffset) {
52036
+ while (stackPointer$2-- > stackOffset) {
52037
52037
 
52038
52038
  visitCount++;
52039
52039
 
52040
- n = stack$7[stackPointer$3];
52040
+ n = stack$6[stackPointer$2];
52041
52041
 
52042
52042
  if (n.isLeafNode) {
52043
52043
  visitor.call(thisArg, n);
52044
52044
  } else {
52045
52045
  //a binary node
52046
52046
  if (n.right !== null) {
52047
- stack$7[stackPointer$3++] = n.right;
52047
+ stack$6[stackPointer$2++] = n.right;
52048
52048
  }
52049
52049
  if (n.left !== null) {
52050
- stack$7[stackPointer$3++] = n.left;
52050
+ stack$6[stackPointer$2++] = n.left;
52051
52051
  }
52052
52052
  }
52053
52053
  }
52054
52054
 
52055
52055
  // drop stack frame
52056
- stackPointer$3 = stackOffset;
52056
+ stackPointer$2 = stackOffset;
52057
52057
 
52058
52058
  return visitCount;
52059
52059
  }
@@ -52622,15 +52622,15 @@ class BinaryNode extends Node {
52622
52622
  * @returns {number} number of objects added to the result
52623
52623
  */
52624
52624
  requestLeafIntersectionsAABB3(result, x0, y0, z0, x1, y1, z1) {
52625
- const startOffset = stackPointer$3;
52625
+ const startOffset = stackPointer$2;
52626
52626
 
52627
- stack$7[stackPointer$3++] = this;
52627
+ stack$6[stackPointer$2++] = this;
52628
52628
 
52629
52629
  let count = 0;
52630
52630
 
52631
- while (stackPointer$3 > startOffset) {
52632
- stackPointer$3--;
52633
- const node = stack$7[stackPointer$3];
52631
+ while (stackPointer$2 > startOffset) {
52632
+ stackPointer$2--;
52633
+ const node = stack$6[stackPointer$2];
52634
52634
 
52635
52635
  if (!aabb3_intersect_aabb3(
52636
52636
  x0, y0, z0, x1, y1, z1,
@@ -52647,12 +52647,12 @@ class BinaryNode extends Node {
52647
52647
  } else {
52648
52648
  const left = node.left;
52649
52649
  if (left !== null) {
52650
- stack$7[stackPointer$3++] = left;
52650
+ stack$6[stackPointer$2++] = left;
52651
52651
  }
52652
52652
 
52653
52653
  const right = node.right;
52654
52654
  if (right !== null) {
52655
- stack$7[stackPointer$3++] = right;
52655
+ stack$6[stackPointer$2++] = right;
52656
52656
  }
52657
52657
  }
52658
52658
  }
@@ -56117,16 +56117,16 @@ class IndexedBinaryBVH {
56117
56117
  */
56118
56118
  traversePreOrderStack(visitor, startIndex) {
56119
56119
 
56120
- const stackOffset = stackPointer$2;
56120
+ const stackOffset = stackPointer$1;
56121
56121
 
56122
- stack$6[stackPointer$2++] = startIndex;
56122
+ stack$5[stackPointer$1++] = startIndex;
56123
56123
 
56124
56124
  const nodeThreshold = this.binaryNodeCount * 6;
56125
56125
  const endAddress = this.boxCount * 6;
56126
56126
 
56127
- while (stackPointer$2-- > stackOffset) {
56127
+ while (stackPointer$1-- > stackOffset) {
56128
56128
 
56129
- const index = stack$6[stackPointer$2];
56129
+ const index = stack$5[stackPointer$1];
56130
56130
 
56131
56131
  const address = index * 6;
56132
56132
 
@@ -56142,7 +56142,7 @@ class IndexedBinaryBVH {
56142
56142
  //right
56143
56143
  if (rightAddress < endAddress) {
56144
56144
  if (rightAddress < nodeThreshold) {
56145
- stack$6[stackPointer$2++] = rightIndex;
56145
+ stack$5[stackPointer$1++] = rightIndex;
56146
56146
  } else {
56147
56147
  visitor.visit(rightAddress, NodeType.LEAF);
56148
56148
  }
@@ -56151,7 +56151,7 @@ class IndexedBinaryBVH {
56151
56151
  //left
56152
56152
  if (leftAddress < endAddress) {
56153
56153
  if (leftAddress < nodeThreshold) {
56154
- stack$6[stackPointer$2++] = leftIndex;
56154
+ stack$5[stackPointer$1++] = leftIndex;
56155
56155
  } else {
56156
56156
  visitor.visit(leftAddress, NodeType.LEAF);
56157
56157
  }
@@ -56160,7 +56160,7 @@ class IndexedBinaryBVH {
56160
56160
  }
56161
56161
 
56162
56162
  //drop stack
56163
- stackPointer$2 = stackOffset;
56163
+ stackPointer$1 = stackOffset;
56164
56164
  }
56165
56165
 
56166
56166
  /**
@@ -56327,8 +56327,8 @@ function binaryNodeRefit(array, binaryNode, childNode0, childNode1) {
56327
56327
  }
56328
56328
 
56329
56329
 
56330
- const stack$6 = [];
56331
- let stackPointer$2 = 0;
56330
+ const stack$5 = [];
56331
+ let stackPointer$1 = 0;
56332
56332
 
56333
56333
  const rayLeafIntersectionVisitor = new RayLeafIntersectionVisitor();
56334
56334
 
@@ -56616,18 +56616,20 @@ function rayTriangleIntersection(result, rayOrigin, rayDirection, a, b, c) {
56616
56616
  /**
56617
56617
  *
56618
56618
  * @param {number[]|ArrayLike<number>|Float32Array} output 6 component vector, [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]
56619
+ * @param {number} output_offset
56619
56620
  * @param {number[]|ArrayLike<number>|Float32Array} input 6 component vector, [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]
56621
+ * @param {number} input_offset
56620
56622
  * @param {number[]|ArrayLike<number>|Float32Array} m4 4x4 matrix
56621
56623
  * @returns {boolean} false if matrix transformation is impossible, such as when scale of the matrix is 0
56622
56624
  */
56623
- function ray3_array_apply_matrix4(output, input, m4) {
56624
- const origin_x = input[0];
56625
- const origin_y = input[1];
56626
- const origin_z = input[2];
56625
+ function ray3_array_apply_matrix4(output, output_offset, input, input_offset, m4) {
56626
+ const origin_x = input[input_offset + 0];
56627
+ const origin_y = input[input_offset + 1];
56628
+ const origin_z = input[input_offset + 2];
56627
56629
 
56628
- const direction_x = input[3];
56629
- const direction_y = input[4];
56630
- const direction_z = input[5];
56630
+ const direction_x = input[input_offset + 3];
56631
+ const direction_y = input[input_offset + 4];
56632
+ const direction_z = input[input_offset + 5];
56631
56633
 
56632
56634
  // transform ray to local space (inlined for speed)
56633
56635
  const det = m4[3] * origin_x + m4[7] * origin_y + m4[11] * origin_z + m4[15];
@@ -56659,13 +56661,13 @@ function ray3_array_apply_matrix4(output, input, m4) {
56659
56661
  const out_direction_normalized_y = out_direction_y * out_direction_magnitude_inverse;
56660
56662
  const out_direction_normalized_z = out_direction_z * out_direction_magnitude_inverse;
56661
56663
 
56662
- output[0] = out_origin_x;
56663
- output[1] = out_origin_y;
56664
- output[2] = out_origin_z;
56664
+ output[output_offset + 0] = out_origin_x;
56665
+ output[output_offset + 1] = out_origin_y;
56666
+ output[output_offset + 2] = out_origin_z;
56665
56667
 
56666
- output[3] = out_direction_normalized_x;
56667
- output[4] = out_direction_normalized_y;
56668
- output[5] = out_direction_normalized_z;
56668
+ output[output_offset + 3] = out_direction_normalized_x;
56669
+ output[output_offset + 4] = out_direction_normalized_y;
56670
+ output[output_offset + 5] = out_direction_normalized_z;
56669
56671
 
56670
56672
  return true;
56671
56673
  }
@@ -56883,7 +56885,7 @@ class BVHGeometryRaycaster {
56883
56885
  directionX, directionY, directionZ
56884
56886
  );
56885
56887
 
56886
- ray3_array_apply_matrix4(ray_tmp, ray_tmp, m4_tmp);
56888
+ ray3_array_apply_matrix4(ray_tmp, 0,ray_tmp,0, m4_tmp);
56887
56889
 
56888
56890
  const _originX = ray_tmp[0];
56889
56891
  const _originY = ray_tmp[1];
@@ -60530,8 +60532,9 @@ class MapEntry {
60530
60532
  *
60531
60533
  * @param {K} key
60532
60534
  * @param {V} value
60535
+ * @param {number} hash
60533
60536
  */
60534
- constructor(key, value) {
60537
+ constructor(key, value, hash) {
60535
60538
  /**
60536
60539
  *
60537
60540
  * @type {K}
@@ -60542,6 +60545,12 @@ class MapEntry {
60542
60545
  * @type {V}
60543
60546
  */
60544
60547
  this.value = value;
60548
+
60549
+ /**
60550
+ *
60551
+ * @type {number}
60552
+ */
60553
+ this.hash = hash;
60545
60554
  }
60546
60555
  }
60547
60556
 
@@ -60738,7 +60747,11 @@ class HashMap {
60738
60747
 
60739
60748
  const entryKey = entry.key;
60740
60749
 
60741
- if (entryKey === key || this.keyEqualityFunction(entryKey, key)) {
60750
+
60751
+ if (
60752
+ entry.hash === raw_hash
60753
+ && (entryKey === key || this.keyEqualityFunction(entryKey, key))
60754
+ ) {
60742
60755
 
60743
60756
  // found record with matching key, replace the value
60744
60757
 
@@ -60753,7 +60766,7 @@ class HashMap {
60753
60766
 
60754
60767
  }
60755
60768
 
60756
- bucket.push(new MapEntry(key, value));
60769
+ bucket.push(new MapEntry(key, value,raw_hash));
60757
60770
 
60758
60771
  const old_size = this.size;
60759
60772
  const new_size = old_size + 1;
@@ -60788,8 +60801,10 @@ class HashMap {
60788
60801
 
60789
60802
  const entryKey = entry.key;
60790
60803
 
60791
- if (entryKey === key || this.keyEqualityFunction(entryKey, key)) {
60792
-
60804
+ if (
60805
+ entry.hash === raw_hash
60806
+ && (entryKey === key || this.keyEqualityFunction(entryKey, key))
60807
+ ) {
60793
60808
  return entry.value;
60794
60809
 
60795
60810
  }
@@ -60951,6 +60966,9 @@ class HashMap {
60951
60966
 
60952
60967
  //check hash
60953
60968
  const raw_hash = this.keyHashFunction(entry.key);
60969
+
60970
+ entry.hash = raw_hash;
60971
+
60954
60972
  const actual_bucket_index = this.__compute_bucket_index(raw_hash);
60955
60973
 
60956
60974
 
@@ -69972,6 +69990,70 @@ class GeometrySpatialQueryAccelerator {
69972
69990
  */
69973
69991
  GeometrySpatialQueryAccelerator.INSTANCE = new GeometrySpatialQueryAccelerator();
69974
69992
 
69993
+ /**
69994
+ * A convenience class to work with BVH leaf nodes
69995
+ */
69996
+ class EBBVHLeafProxy {
69997
+ /**
69998
+ *
69999
+ * @type {ExplicitBinaryBoundingVolumeHierarchy|null}
70000
+ */
70001
+ #tree = null;
70002
+
70003
+ /**
70004
+ *
70005
+ * @type {number}
70006
+ */
70007
+ #node_id = -1;
70008
+
70009
+ /**
70010
+ * @readonly
70011
+ * @type {number[]}
70012
+ */
70013
+ bounds = new Float32Array(6);
70014
+
70015
+ get is_linked() {
70016
+ return this.#node_id !== -1;
70017
+ }
70018
+
70019
+ /**
70020
+ *
70021
+ * @param {ExplicitBinaryBoundingVolumeHierarchy} tree
70022
+ * @param {number} data Must be a uint32
70023
+ */
70024
+ link(tree, data) {
70025
+ assert.defined(tree, 'tree');
70026
+ assert.isNonNegativeInteger(data, 'data');
70027
+
70028
+ this.#tree = tree;
70029
+
70030
+ const node_id = tree.allocate_node();
70031
+
70032
+ this.#node_id = node_id;
70033
+
70034
+ tree.node_set_aabb(node_id, this.bounds);
70035
+ tree.node_set_user_data(node_id, data);
70036
+ tree.insert_leaf(node_id);
70037
+ }
70038
+
70039
+ unlink() {
70040
+ this.#tree.remove_leaf(this.#node_id);
70041
+ this.#tree.release_node(this.#node_id);
70042
+
70043
+ this.#node_id = -1;
70044
+ this.#tree = null;
70045
+ }
70046
+
70047
+ write_bounds() {
70048
+ if (this.#tree === null) {
70049
+ // nothing to write to
70050
+ return;
70051
+ }
70052
+
70053
+ this.#tree.node_move_aabb(this.#node_id, this.bounds);
70054
+ }
70055
+ }
70056
+
69975
70057
  /**
69976
70058
  * @readonly
69977
70059
  * @type {Float32Array}
@@ -70020,26 +70102,7 @@ class ShadedGeometry {
70020
70102
  */
70021
70103
  this.depth_material = null;
70022
70104
 
70023
- /**
70024
- *
70025
- * @type {number}
70026
- * @private
70027
- */
70028
- this.__bvh_leaf_id = -1;
70029
-
70030
- /**
70031
- *
70032
- * @type {ExplicitBinaryBoundingVolumeHierarchy|null}
70033
- * @private
70034
- */
70035
- this.__bvh_tree = null;
70036
-
70037
- /**
70038
- * @readonly
70039
- * @type {number[]|Float32Array}
70040
- * @private
70041
- */
70042
- this.__bvh_aabb = new Float32Array(6);
70105
+ this.__bvh_leaf = new EBBVHLeafProxy();
70043
70106
 
70044
70107
  /**
70045
70108
  * Transient, assigned in the system
@@ -70205,7 +70268,7 @@ class ShadedGeometry {
70205
70268
  * @param {AABB3} destination
70206
70269
  */
70207
70270
  getBoundingBox(destination) {
70208
- const aabb = this.__bvh_aabb;
70271
+ const aabb = this.__bvh_leaf.bounds;
70209
70272
 
70210
70273
  destination.readFromArray(aabb);
70211
70274
  }
@@ -70245,7 +70308,7 @@ class ShadedGeometry {
70245
70308
  updateTransform() {
70246
70309
  this.update_bounds();
70247
70310
 
70248
- this.__bvh_tree.node_move_aabb(this.__bvh_leaf_id, this.__bvh_aabb);
70311
+ this.__bvh_leaf.write_bounds();
70249
70312
  }
70250
70313
 
70251
70314
  update_bounds() {
@@ -70282,7 +70345,7 @@ class ShadedGeometry {
70282
70345
  scratch_aabb3_array[4] = y1;
70283
70346
  scratch_aabb3_array[5] = z1;
70284
70347
 
70285
- aabb3_matrix4_project(this.__bvh_aabb, scratch_aabb3_array, this.transform);
70348
+ aabb3_matrix4_project(this.__bvh_leaf.bounds, scratch_aabb3_array, this.transform);
70286
70349
  }
70287
70350
 
70288
70351
  /**
@@ -70298,7 +70361,7 @@ class ShadedGeometry {
70298
70361
  invert(scratch_m4, transform_matrix4);
70299
70362
 
70300
70363
  // transform ray to local space
70301
- if (!ray3_array_apply_matrix4(scratch_ray_0$1, ray, scratch_m4)) {
70364
+ if (!ray3_array_apply_matrix4(scratch_ray_0$1,0, ray,0, scratch_m4)) {
70302
70365
  // invalid transform matrix
70303
70366
  return false;
70304
70367
  }
@@ -76255,15 +76318,11 @@ class SGMeshSystem extends System {
76255
76318
 
76256
76319
  entity_node.build(ecd);
76257
76320
 
76258
- transform.position.onChanged.add(copy_transform);
76259
- transform.rotation.onChanged.add(copy_transform);
76260
- transform.scale.onChanged.add(copy_transform);
76321
+ transform.subscribeAllChanges(copy_transform);
76261
76322
 
76262
76323
  entity_node.on.destroyed.addOne(() => {
76263
76324
 
76264
- transform.position.onChanged.remove(copy_transform);
76265
- transform.rotation.onChanged.remove(copy_transform);
76266
- transform.scale.onChanged.remove(copy_transform);
76325
+ transform.unsubscribeAllChanges(copy_transform);
76267
76326
 
76268
76327
  });
76269
76328
 
@@ -78829,6 +78888,7 @@ class ExplicitBinaryBoundingVolumeHierarchy {
78829
78888
  */
78830
78889
  node_set_user_data(id, value) {
78831
78890
  assert.isNonNegativeInteger(id, 'id');
78891
+ assert.isNonNegativeInteger(value, 'value');
78832
78892
 
78833
78893
  this.__data_uint32[ELEMENT_WORD_COUNT * id + COLUMN_USER_DATA] = value;
78834
78894
  }
@@ -80542,25 +80602,13 @@ class ShadedGeometrySystem extends System {
80542
80602
 
80543
80603
  sg.update_bounds();
80544
80604
 
80545
- t.position.onChanged.add(sg.updateTransform, sg);
80546
- t.rotation.onChanged.add(sg.updateTransform, sg);
80547
- t.scale.onChanged.add(sg.updateTransform, sg);
80605
+ t.subscribeAllChanges(sg.updateTransform, sg);
80548
80606
 
80549
80607
  // remember entity for lookups
80550
80608
  sg.__entity = entity;
80551
80609
 
80552
80610
  // insert BVH entry
80553
- const bvh = this.__bvh_binary;
80554
-
80555
- const bvh_node_id = bvh.allocate_node();
80556
-
80557
- bvh.node_set_aabb(bvh_node_id, sg.__bvh_aabb);
80558
- bvh.node_set_user_data(bvh_node_id, entity);
80559
- bvh.insert_leaf(bvh_node_id);
80560
-
80561
- sg.__bvh_tree = bvh;
80562
- sg.__bvh_leaf_id = bvh_node_id;
80563
-
80611
+ sg.__bvh_leaf.link(this.__bvh_binary, entity);
80564
80612
 
80565
80613
  // update usage count
80566
80614
  const geometry_id = sg.geometry.id;
@@ -80577,19 +80625,10 @@ class ShadedGeometrySystem extends System {
80577
80625
  * @param {number} entity
80578
80626
  */
80579
80627
  unlink(sg, t, entity) {
80580
- t.position.onChanged.remove(sg.updateTransform, sg);
80581
- t.rotation.onChanged.remove(sg.updateTransform, sg);
80582
- t.scale.onChanged.remove(sg.updateTransform, sg);
80628
+ t.unsubscribeAllChanges(sg.updateTransform, sg);
80583
80629
 
80584
80630
  // disconnect BVH
80585
- const node_id = sg.__bvh_leaf_id;
80586
-
80587
- this.__bvh_binary.remove_leaf(node_id);
80588
- this.__bvh_binary.release_node(node_id);
80589
-
80590
- // reset BVH references
80591
- sg.__bvh_leaf_id = -1;
80592
- sg.__bvh_tree = null;
80631
+ sg.__bvh_leaf.unlink();
80593
80632
 
80594
80633
  const geometry_id = sg.geometry.id;
80595
80634
  const count_existing = this.__geometry_usage_counters.get(geometry_id);
@@ -87567,8 +87606,8 @@ function compare_three_objects(a, b) {
87567
87606
  *
87568
87607
  * @type {(BinaryNode|LeafNode)[]}
87569
87608
  */
87570
- const stack$5 = [];
87571
- let stackPointer$1 = 0;
87609
+ const stack$4 = [];
87610
+ let stackPointer = 0;
87572
87611
 
87573
87612
  /**
87574
87613
  * @template T
@@ -87580,22 +87619,22 @@ function queryBinaryNode_CollectData(destination, destinationOffset, root) {
87580
87619
  let n;
87581
87620
  let i = 0;
87582
87621
 
87583
- const stackOffset = stackPointer$1;
87622
+ const stackOffset = stackPointer;
87584
87623
 
87585
- stack$5[stackPointer$1++] = root;
87624
+ stack$4[stackPointer++] = root;
87586
87625
 
87587
- while (stackPointer$1-- > stackOffset) {
87626
+ while (stackPointer-- > stackOffset) {
87588
87627
 
87589
- n = stack$5[stackPointer$1];
87628
+ n = stack$4[stackPointer];
87590
87629
 
87591
87630
  if (n.isBinaryNode) {
87592
87631
 
87593
87632
  if (n.right !== null) {
87594
- stack$5[stackPointer$1++] = n.right;
87633
+ stack$4[stackPointer++] = n.right;
87595
87634
  }
87596
87635
 
87597
87636
  if (n.left !== null) {
87598
- stack$5[stackPointer$1++] = n.left;
87637
+ stack$4[stackPointer++] = n.left;
87599
87638
  }
87600
87639
 
87601
87640
  } else {
@@ -87608,7 +87647,7 @@ function queryBinaryNode_CollectData(destination, destinationOffset, root) {
87608
87647
  }
87609
87648
 
87610
87649
  //drop the stack frame
87611
- stackPointer$1 = stackOffset;
87650
+ stackPointer = stackOffset;
87612
87651
 
87613
87652
  return i;
87614
87653
  }
@@ -87617,7 +87656,7 @@ function queryBinaryNode_CollectData(destination, destinationOffset, root) {
87617
87656
  *
87618
87657
  * @type {(BinaryNode|LeafNode)[]}
87619
87658
  */
87620
- const stack$4 = [];
87659
+ const stack$3 = [];
87621
87660
 
87622
87661
 
87623
87662
  /**
@@ -87637,13 +87676,13 @@ function queryBinaryNode_FrustumIntersections_Data(destination, destination_offs
87637
87676
  let offset = destination_offset;
87638
87677
  let stackPointer = 1;
87639
87678
 
87640
- stack$4[0] = root;
87679
+ stack$3[0] = root;
87641
87680
 
87642
87681
  while (stackPointer > 0) {
87643
87682
 
87644
87683
  stackPointer--;
87645
87684
 
87646
- n = stack$4[stackPointer];
87685
+ n = stack$3[stackPointer];
87647
87686
 
87648
87687
  const intersection_degree = aabb3_intersects_frustum_degree(
87649
87688
  n.x0, n.y0, n.z0,
@@ -87664,13 +87703,13 @@ function queryBinaryNode_FrustumIntersections_Data(destination, destination_offs
87664
87703
  const right = n.right;
87665
87704
 
87666
87705
  if (right !== null) {
87667
- stack$4[stackPointer++] = right;
87706
+ stack$3[stackPointer++] = right;
87668
87707
  }
87669
87708
 
87670
87709
  const left = n.left;
87671
87710
 
87672
87711
  if (left !== null) {
87673
- stack$4[stackPointer++] = left;
87712
+ stack$3[stackPointer++] = left;
87674
87713
  }
87675
87714
 
87676
87715
  } else {
@@ -88632,7 +88671,7 @@ const MetricsCategory = {
88632
88671
  System: "system"
88633
88672
  };
88634
88673
 
88635
- const stack$3 = [];
88674
+ const stack$2 = [];
88636
88675
 
88637
88676
  class ThreeBypassRenderer {
88638
88677
  constructor() {
@@ -88709,13 +88748,13 @@ class ThreeBypassRenderer {
88709
88748
  const object3D = input[i];
88710
88749
 
88711
88750
  if (input_filter(object3D)) {
88712
- stack$3[stack_top++] = object3D;
88751
+ stack$2[stack_top++] = object3D;
88713
88752
  }
88714
88753
 
88715
88754
  }
88716
88755
 
88717
88756
  while (stack_top > 0) {
88718
- const object3D = stack$3[--stack_top];
88757
+ const object3D = stack$2[--stack_top];
88719
88758
 
88720
88759
  if (
88721
88760
  object_filter(object3D)
@@ -88754,7 +88793,7 @@ class ThreeBypassRenderer {
88754
88793
  for (i = 0; i < child_count; i++) {
88755
88794
  const child = children[i];
88756
88795
 
88757
- stack$3[stack_top++] = child;
88796
+ stack$2[stack_top++] = child;
88758
88797
  }
88759
88798
  }
88760
88799
 
@@ -99904,6 +99943,9 @@ class ActionBehavior extends Behavior {
99904
99943
  }
99905
99944
  }
99906
99945
 
99946
+ /**
99947
+ * Abstract class
99948
+ */
99907
99949
  class CompositeBehavior extends Behavior {
99908
99950
  constructor() {
99909
99951
  super();
@@ -99921,12 +99963,25 @@ class CompositeBehavior extends Behavior {
99921
99963
  * @param {Behavior} child
99922
99964
  */
99923
99965
  addChild(child) {
99924
- assert.defined(child);
99925
- assert.ok(child.isBehavior, 'child is not a Behavior');
99966
+ assert.defined(child, 'child');
99967
+ assert.notNull(child, 'child');
99968
+ assert.equal(child.isBehavior, true, 'child is not a Behavior');
99926
99969
 
99927
99970
  this.__children.push(child);
99928
99971
  }
99929
99972
 
99973
+ /**
99974
+ *
99975
+ * @param {Behavior[]} many
99976
+ */
99977
+ addChildren(many) {
99978
+ const n = many.length;
99979
+ for (let i = 0; i < n; i++) {
99980
+ const e = many[i];
99981
+ this.addChild(e);
99982
+ }
99983
+ }
99984
+
99930
99985
  /**
99931
99986
  * NOTE: do not modify obtained value
99932
99987
  * @return {Behavior[]}
@@ -99964,6 +100019,10 @@ class CompositeBehavior extends Behavior {
99964
100019
  */
99965
100020
  CompositeBehavior.prototype.isCompositeBehavior = true;
99966
100021
 
100022
+ /**
100023
+ * Executes all contained behaviors one after another in a sequence, next behaviour in the sequence will not be started until the previous one signal success
100024
+ * If any of the contained behaviours fail - the whole sequence fails
100025
+ */
99967
100026
  class SequenceBehavior extends CompositeBehavior {
99968
100027
  constructor() {
99969
100028
  super();
@@ -100067,7 +100126,7 @@ class SequenceBehavior extends CompositeBehavior {
100067
100126
  static from(list) {
100068
100127
  const r = new SequenceBehavior();
100069
100128
 
100070
- list.forEach(b => r.addChild(b));
100129
+ r.addChildren(list);
100071
100130
 
100072
100131
  return r;
100073
100132
  }
@@ -115168,7 +115227,9 @@ var FrustumProjector = {
115168
115227
  projectInWorldSpace
115169
115228
  };
115170
115229
 
115171
- class PointLightData {
115230
+ class LightRenderMetadata {
115231
+
115232
+
115172
115233
  /**
115173
115234
  *
115174
115235
  * @param {AbstractLight} light
@@ -115186,12 +115247,12 @@ class PointLightData {
115186
115247
  */
115187
115248
  this.address = 0;
115188
115249
 
115189
- this.bvh_leaf_main = new LeafNode(this, 0, 0, 0, 0, 0, 0);
115250
+ this.bvh_leaf = new EBBVHLeafProxy();
115190
115251
  }
115191
115252
 
115192
115253
  /**
115193
115254
  *
115194
- * @param {PointLightData} other
115255
+ * @param {LightRenderMetadata} other
115195
115256
  * @returns {number}
115196
115257
  */
115197
115258
  compare(other) {
@@ -115199,17 +115260,20 @@ class PointLightData {
115199
115260
  }
115200
115261
 
115201
115262
  update() {
115263
+ const leaf = this.bvh_leaf;
115202
115264
 
115203
- const leaf = this.bvh_leaf_main;
115265
+ this.light.getAABB(leaf.bounds);
115204
115266
 
115205
- this.light.getAABB(leaf);
115206
-
115207
- if (leaf.parentNode !== null) {
115208
- leaf.parentNode.bubbleRefit();
115209
- }
115267
+ leaf.write_bounds();
115210
115268
  }
115211
115269
 
115212
- link() {
115270
+ /**
115271
+ *
115272
+ * @param {ExplicitBinaryBoundingVolumeHierarchy} bvh
115273
+ */
115274
+ link(bvh) {
115275
+ this.bvh_leaf.link(bvh, this.light.id);
115276
+
115213
115277
  this.update();
115214
115278
 
115215
115279
  this.light.onDimensionChanged(this.update, this);
@@ -115220,488 +115284,10 @@ class PointLightData {
115220
115284
  this.light.offDimensionChanged(this.update, this);
115221
115285
 
115222
115286
  // disconnect from bvh
115223
- this.bvh_leaf_main.disconnect();
115224
- }
115225
- }
115226
-
115227
- const _lut_array_buffer = new ArrayBuffer(84);
115228
- /**
115229
- * Mapping from 3 plane bitfield, corresponding to intersection point of the planes
115230
- * @type {number[]}
115231
- */
115232
- const triplanar_corner_mapping = new Uint8Array(_lut_array_buffer, 0, 43);
115233
-
115234
- triplanar_corner_mapping[0b010101] = 0;
115235
- triplanar_corner_mapping[0b100101] = 1;
115236
- triplanar_corner_mapping[0b011001] = 2;
115237
- triplanar_corner_mapping[0b101001] = 3;
115238
- triplanar_corner_mapping[0b010110] = 4;
115239
- triplanar_corner_mapping[0b100110] = 5;
115240
- triplanar_corner_mapping[0b011010] = 6;
115241
- triplanar_corner_mapping[0b101010] = 7;
115242
- /**
115243
- * Mapping from 2 plane bitfield to 2 corner bitfield, corresponding to corner indices of intersecting planes
115244
- * @type {number[]}
115245
- */
115246
- const biplanar_edge_mapping = new Uint8Array(_lut_array_buffer, 43, 41);
115247
-
115248
- biplanar_edge_mapping[0b000101] = 0 | (1 << 3);
115249
- biplanar_edge_mapping[0b000110] = 4 | (5 << 3);
115250
-
115251
- biplanar_edge_mapping[0b001001] = 2 | (3 << 3);
115252
- biplanar_edge_mapping[0b001010] = 6 | (7 << 3);
115253
-
115254
- biplanar_edge_mapping[0b010100] = 0 | (4 << 3);
115255
- biplanar_edge_mapping[0b011000] = 2 | (6 << 3);
115256
-
115257
- biplanar_edge_mapping[0b100100] = 1 | (5 << 3);
115258
- biplanar_edge_mapping[0b101000] = 3 | (7 << 3);
115259
-
115260
- biplanar_edge_mapping[0b010001] = 0 | (2 << 3);
115261
- biplanar_edge_mapping[0b010010] = 4 | (6 << 3);
115262
-
115263
- biplanar_edge_mapping[0b100001] = 1 | (3 << 3);
115264
- biplanar_edge_mapping[0b100010] = 5 | (7 << 3);
115265
-
115266
- /**
115267
- * Computes shortest distance between a line segment(defined by 2 points) and a point
115268
- * @param {number} x0
115269
- * @param {number} y0
115270
- * @param {number} z0
115271
- * @param {number} x1
115272
- * @param {number} y1
115273
- * @param {number} z1
115274
- * @param {number} px
115275
- * @param {number} py
115276
- * @param {number} pz
115277
- */
115278
- function line3_computeSegmentPointDistance_sqr(x0, y0, z0, x1, y1, z1, px, py, pz) {
115279
- // get line delta
115280
- const line_delta_x = x1 - x0;
115281
- const line_delta_y = y1 - y0;
115282
- const line_delta_z = z1 - z0;
115283
-
115284
- // find closest point
115285
- const sp0_x = px - x0;
115286
- const sp0_y = py - y0;
115287
- const sp0_z = pz - z0;
115288
-
115289
- //
115290
- const d2 = line_delta_x * line_delta_x + line_delta_y * line_delta_y + line_delta_z * line_delta_z;
115291
-
115292
- const d3 = line_delta_x * sp0_x + line_delta_y * sp0_y + line_delta_z * sp0_z;
115293
-
115294
- const t = clamp01(d3 / d2);
115295
-
115296
- // compute point on the line
115297
- const lp_x = line_delta_x * t + x0;
115298
- const lp_y = line_delta_y * t + y0;
115299
- const lp_z = line_delta_z * t + z0;
115300
-
115301
- // compute distance from the point in question to the point on the line
115302
- return v3_distance_sqr(px, py, pz, lp_x, lp_y, lp_z);
115303
- }
115304
-
115305
- /**
115306
- *
115307
- * @param {number} radius
115308
- * @param {number} light_x
115309
- * @param {number} light_y
115310
- * @param {number} light_z
115311
- * @param {number} outside_plane_count
115312
- * @param {number} outside_plane_bitfield
115313
- * @param {number[]} points
115314
- * @return {boolean}
115315
- */
115316
- function detailed_sphere_frustum_intersection_test(
115317
- radius, light_x, light_y, light_z,
115318
- outside_plane_count, outside_plane_bitfield,
115319
- points
115320
- ) {
115321
-
115322
- const radius_sqr = radius * radius;
115323
-
115324
- if (outside_plane_count === 3) {
115325
- // nearest point in a corner, find the corner
115326
- const point_index = triplanar_corner_mapping[outside_plane_bitfield];
115327
-
115328
- const point_address = point_index * 3;
115329
-
115330
- const point_x = points[point_address];
115331
- const point_y = points[point_address + 1];
115332
- const point_z = points[point_address + 2];
115333
-
115334
- const distance_to_light_sqr = v3_distance_sqr(
115335
- point_x, point_y, point_z,
115336
- light_x, light_y, light_z
115337
- );
115338
-
115339
- // query_bvh_frustum_from_objects.checks_sphere_frustum_corner++;
115340
-
115341
- // return distance_to_light_sqr <= radius_sqr;
115342
-
115343
- if (distance_to_light_sqr > radius_sqr) {
115344
-
115345
- // query_bvh_frustum_from_objects.rejection_sphere_count++;
115346
- return false;
115347
- }
115348
-
115349
- } else if (outside_plane_count === 2) {
115350
- // nearest point is on an edge of two plane intersection
115351
- const edge_bitfield = biplanar_edge_mapping[outside_plane_bitfield];
115352
-
115353
- // get 2 corners from edge bitfield
115354
- const corner_index_0 = edge_bitfield & 0b111;
115355
- const corner_address_0 = corner_index_0 * 3;
115356
-
115357
- const corner_index_1 = (edge_bitfield >> 3) & 0b111;
115358
- const corner_address_1 = corner_index_1 * 3;
115359
-
115360
- const point_0_x = points[corner_address_0];
115361
- const point_0_y = points[corner_address_0 + 1];
115362
- const point_0_z = points[corner_address_0 + 2];
115363
-
115364
- const point_1_x = points[corner_address_1];
115365
- const point_1_y = points[corner_address_1 + 1];
115366
- const point_1_z = points[corner_address_1 + 2];
115367
-
115368
- const distance_to_frustum_sqr = line3_computeSegmentPointDistance_sqr(
115369
- point_0_x, point_0_y, point_0_z,
115370
- point_1_x, point_1_y, point_1_z,
115371
- light_x, light_y, light_z
115372
- );
115373
-
115374
- // query_bvh_frustum_from_objects.checks_sphere_frustum_edge++;
115375
-
115376
- // return distance_to_frustum_sqr <= radius_sqr;
115377
-
115378
- if (distance_to_frustum_sqr > radius_sqr) {
115379
-
115380
- // query_bvh_frustum_from_objects.rejection_sphere_count++;
115381
- return false;
115382
- }
115287
+ this.bvh_leaf.unlink();
115383
115288
  }
115384
-
115385
- return true;
115386
115289
  }
115387
115290
 
115388
- /**
115389
- *
115390
- * @param {number} light_x
115391
- * @param {number} light_y
115392
- * @param {number} light_z
115393
- * @param {number} radius
115394
- * @param {number[]} points
115395
- * @param {number[]|Float32Array|Float64Array} planes
115396
- * @returns {boolean}
115397
- */
115398
- function point_light_inside_volume(
115399
- light_x, light_y, light_z, radius,
115400
- points, planes
115401
- ) {
115402
- let j = 0;
115403
- let outside_plane_count = 0;
115404
- let outside_plane_bitfield = 0;
115405
-
115406
- // validate if the sphere intersects the plane-bound space
115407
-
115408
- // query_bvh_frustum_from_objects.checks_sphere++;
115409
-
115410
- for (; j < 6; j++) {
115411
-
115412
- const plane_address = j * 4;
115413
-
115414
- const plane_normal_x = planes[plane_address];
115415
- const plane_normal_y = planes[plane_address + 1];
115416
- const plane_normal_z = planes[plane_address + 2];
115417
- const plane_constant = planes[plane_address + 3];
115418
-
115419
- /*
115420
- compute distance from the center of the sphere to the plane
115421
- NOTE: inlined computation of distance from point to plane
115422
- */
115423
- const distance = (plane_normal_x * light_x + plane_normal_y * light_y + plane_normal_z * light_z) + plane_constant;
115424
-
115425
- // query_bvh_frustum_from_objects.checks_sphere_plane++;
115426
-
115427
- if (distance < 0) {
115428
- // center of the sphere is below the plane
115429
-
115430
- if (distance >= -radius) {
115431
-
115432
- // sphere intersects the plane
115433
-
115434
- outside_plane_count++;
115435
-
115436
- const plane_bit_mask = 1 << j;
115437
-
115438
- outside_plane_bitfield |= plane_bit_mask;
115439
- } else {
115440
- // sphere is entirely below the plane
115441
-
115442
- // query_bvh_frustum_from_objects.rejection_sphere_count++;
115443
-
115444
- return false;
115445
- }
115446
- }
115447
-
115448
- }
115449
-
115450
- if (outside_plane_count < 2) {
115451
- return true;
115452
- } else {
115453
- return detailed_sphere_frustum_intersection_test(
115454
- radius, light_x, light_y, light_z,
115455
- outside_plane_count, outside_plane_bitfield,
115456
- points
115457
- );
115458
- }
115459
- }
115460
-
115461
- const V1 = new Vector3$1();
115462
- const V2 = new Vector3$1();
115463
-
115464
- /**
115465
- * 2,0,or -2; 2: above, -2 : below, 0 : intersects plane
115466
- * NOTE: used an article by Bart Wronski https://bartwronski.com/2017/04/13/cull-that-cone/
115467
- * @param {number} plane_normal_x
115468
- * @param {number} plane_normal_y
115469
- * @param {number} plane_normal_z
115470
- * @param {number} plane_constant
115471
- * @param {number} originX
115472
- * @param {number} originY
115473
- * @param {number} originZ
115474
- * @param {number} directionX
115475
- * @param {number} directionY
115476
- * @param {number} directionZ
115477
- * @param {number} angle
115478
- * @param {number} length
115479
- * @returns {number}
115480
- */
115481
- function computeConePlaneSide(
115482
- plane_normal_x, plane_normal_y, plane_normal_z,
115483
- plane_constant,
115484
- originX, originY, originZ,
115485
- directionX, directionY, directionZ,
115486
- angle,
115487
- length
115488
- ) {
115489
-
115490
- /*
115491
- ORIGINAL HLSL:
115492
- bool TestConeVsPlane(in float3 origin, in float3 forward, in float size, in float angle, in float4 testPlane)
115493
- {
115494
- const float3 V1 = cross(testPlane.xyz, forward);
115495
- const float3 V2 = cross(V1, forward);
115496
-
115497
- const float3 capRimPoint = origin +
115498
- size * cos(angle) * forward +
115499
- size * sin(angle) * V2;
115500
-
115501
- return dot(float4(capRimPoint, 1.0f), testPlane) >= 0.0f || dot(float4(origin, 1.0f), testPlane) >= 0.0f;
115502
- }
115503
- */
115504
-
115505
- V1._crossVectors(plane_normal_x, plane_normal_y, plane_normal_z, directionX, directionY, directionZ);
115506
- V2._crossVectors(V1.x, V1.y, V1.z, directionX, directionY, directionZ);
115507
-
115508
- const scaled_cos = length * Math.cos(angle);
115509
- const scaled_sin = length * Math.sin(angle);
115510
-
115511
- // compute cap rim point (closest point to the plane on the wide side of the cone)
115512
- V1.set(
115513
- originX + scaled_cos * directionX + scaled_sin * V2.x,
115514
- originY + scaled_cos * directionY + scaled_sin * V2.y,
115515
- originZ + scaled_cos * directionZ + scaled_sin * V2.z
115516
- );
115517
-
115518
- const rim_point_side = v4_dot(
115519
- V1.x, V1.y, V1.z, 1,
115520
- plane_normal_x, plane_normal_y, plane_normal_z, plane_constant
115521
- );
115522
-
115523
- const origin_point_side = v4_dot(
115524
- originX, originY, originZ, 1,
115525
- plane_normal_x, plane_normal_y, plane_normal_z, plane_constant
115526
- );
115527
-
115528
- let result = 0;
115529
-
115530
- if (rim_point_side >= 0) {
115531
- result += 1;
115532
- } else {
115533
- result -= 1;
115534
- }
115535
-
115536
- if (origin_point_side >= 0) {
115537
- result += 1;
115538
- } else {
115539
- result -= 1;
115540
- }
115541
-
115542
- return result;
115543
- }
115544
-
115545
- /**
115546
- *
115547
- * @param {SpotLight} light
115548
- * @param {number[]} points
115549
- * @param {number[]|Float32Array|Float64Array} planes
115550
- * @returns {boolean}
115551
- */
115552
- function spot_light_inside_volume(light, points, planes) {
115553
- for (let j = 0; j < 6; j++) {
115554
-
115555
- const plane_address = j * 4;
115556
-
115557
- const plane_normal_x = planes[plane_address];
115558
- const plane_normal_y = planes[plane_address + 1];
115559
- const plane_normal_z = planes[plane_address + 2];
115560
- const plane_constant = planes[plane_address + 3];
115561
-
115562
- const side = computeConePlaneSide(
115563
- plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
115564
- light.position.x, light.position.y, light.position.z,
115565
- light.direction.x, light.direction.y, light.direction.z,
115566
- light.angle.getValue(), light.distance.getValue()
115567
- );
115568
-
115569
- if (side < 0) {
115570
- return false;
115571
- }
115572
- }
115573
-
115574
- return true;
115575
- }
115576
-
115577
- /**
115578
- *
115579
- * @type {(BinaryNode|LeafNode)[]}
115580
- */
115581
- const stack$2 = [];
115582
-
115583
- let stackPointer = 0;
115584
-
115585
- /**
115586
- * Most of the data is in flat continuous array for cache coherence
115587
- * @param {PointLightData[]} destination
115588
- * @param {number} destination_offset
115589
- * @param {BinaryNode<PointLightData>} root
115590
- * @param {number[]|Float32Array|Float64Array} planes
115591
- * @param {number[]|Float32Array|Float64Array} points
115592
- * @returns {number} number of items added to the destination, non-negative integer
115593
- */
115594
- function query_bvh_frustum_from_objects(
115595
- destination,
115596
- destination_offset,
115597
- root, planes, points
115598
- ) {
115599
- let i = 0;
115600
- let j = 0;
115601
- // read out points
115602
- const stackOffset = stackPointer;
115603
-
115604
- stack$2[stackPointer] = root;
115605
-
115606
- stackPointer++;
115607
-
115608
- stack_loop:while (stackPointer-- > stackOffset) {
115609
-
115610
- // query_bvh_frustum_from_objects.iteration_count++;
115611
-
115612
- const n = stack$2[stackPointer];
115613
-
115614
- if (n.isBinaryNode === true) {
115615
-
115616
- for (j = 0; j < 6; j++) {
115617
-
115618
- const plane_address = j * 4;
115619
-
115620
- const plane_normal_x = planes[plane_address];
115621
- const plane_normal_y = planes[plane_address + 1];
115622
- const plane_normal_z = planes[plane_address + 2];
115623
- const plane_constant = planes[plane_address + 3];
115624
-
115625
- const distanceAbovePlane = aabb3_computeDistanceAbovePlane_max(
115626
- plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
115627
- n.x0, n.y0, n.z0,
115628
- n.x1, n.y1, n.z1
115629
- );
115630
-
115631
- if (distanceAbovePlane < 0) {
115632
- // node is below the plane
115633
-
115634
- // query_bvh_frustum_from_objects.rejection_count++;
115635
-
115636
- continue stack_loop;
115637
- }
115638
- }
115639
-
115640
-
115641
- if (n.right !== null) {
115642
- stack$2[stackPointer] = n.right;
115643
- stackPointer++;
115644
- }
115645
-
115646
- if (n.left !== null) {
115647
- stack$2[stackPointer] = n.left;
115648
- stackPointer++;
115649
- }
115650
-
115651
- } else {
115652
-
115653
- // leaf node
115654
-
115655
- /**
115656
- *
115657
- * @type {PointLightData}
115658
- */
115659
- const light_data = n.object;
115660
-
115661
- const light = light_data.light;
115662
-
115663
- if (light.isPointLight) {
115664
-
115665
- const light_position = light.position;
115666
-
115667
- const light_x = light_position.x;
115668
- const light_y = light_position.y;
115669
- const light_z = light_position.z;
115670
-
115671
- const radius = light.radius.getValue();
115672
-
115673
- if (!point_light_inside_volume(light_x, light_y, light_z, radius, points, planes)) {
115674
- continue;
115675
- }
115676
- } else if (light.isSpotLight) {
115677
- if (!spot_light_inside_volume(light, points, planes)) {
115678
- continue;
115679
- }
115680
- }
115681
-
115682
- destination[destination_offset + i] = light_data;
115683
-
115684
- i++;
115685
- }
115686
-
115687
- }
115688
-
115689
- //drop the stack frame
115690
- stackPointer = stackOffset;
115691
-
115692
- return i;
115693
- }
115694
-
115695
- query_bvh_frustum_from_objects.iteration_count = 0;
115696
- query_bvh_frustum_from_objects.rejection_count = 0;
115697
- query_bvh_frustum_from_objects.rejection_sphere_count = 0;
115698
- query_bvh_frustum_from_objects.plane_tests = 0;
115699
- query_bvh_frustum_from_objects.plane_tests_early_exits = 0;
115700
- query_bvh_frustum_from_objects.checks_sphere = 0;
115701
- query_bvh_frustum_from_objects.checks_sphere_plane = 0;
115702
- query_bvh_frustum_from_objects.checks_sphere_frustum_corner = 0;
115703
- query_bvh_frustum_from_objects.checks_sphere_frustum_edge = 0;
115704
-
115705
115291
  /**
115706
115292
  *
115707
115293
  * @param {number[]} result
@@ -116422,10 +116008,7 @@ function build_morton(data, address, matrix) {
116422
116008
 
116423
116009
  }
116424
116010
 
116425
- const scratch_box_0 = [];
116426
- const scratch_box_1 = [];
116427
- const scratch_box_2 = [];
116428
-
116011
+ const scratch_box_0 = new Float32Array(18);
116429
116012
  const stack$1 = [];
116430
116013
 
116431
116014
  class BinaryUint32BVH {
@@ -116597,16 +116180,16 @@ class BinaryUint32BVH {
116597
116180
  */
116598
116181
  __compute_bounds_area_of_3_boxes(a, b, c) {
116599
116182
  this.readBounds(a, scratch_box_0, 0);
116600
- this.readBounds(b, scratch_box_1, 0);
116601
- this.readBounds(c, scratch_box_2, 0);
116183
+ this.readBounds(b, scratch_box_0, 6);
116184
+ this.readBounds(c, scratch_box_0, 12);
116602
116185
 
116603
- const x0 = min3(scratch_box_0[0], scratch_box_1[0], scratch_box_2[0]);
116604
- const y0 = min3(scratch_box_0[1], scratch_box_1[1], scratch_box_2[1]);
116605
- const z0 = min3(scratch_box_0[2], scratch_box_1[2], scratch_box_2[2]);
116186
+ const x0 = min3(scratch_box_0[0], scratch_box_0[6], scratch_box_0[12]);
116187
+ const y0 = min3(scratch_box_0[1], scratch_box_0[7], scratch_box_0[13]);
116188
+ const z0 = min3(scratch_box_0[2], scratch_box_0[8], scratch_box_0[14]);
116606
116189
 
116607
- const x1 = max3(scratch_box_0[3], scratch_box_1[3], scratch_box_2[3]);
116608
- const y1 = max3(scratch_box_0[4], scratch_box_1[4], scratch_box_2[4]);
116609
- const z1 = max3(scratch_box_0[5], scratch_box_1[5], scratch_box_2[5]);
116190
+ const x1 = max3(scratch_box_0[3], scratch_box_0[9], scratch_box_0[15]);
116191
+ const y1 = max3(scratch_box_0[4], scratch_box_0[10], scratch_box_0[16]);
116192
+ const z1 = max3(scratch_box_0[5], scratch_box_0[11], scratch_box_0[17]);
116610
116193
 
116611
116194
  return aabb3_compute_half_surface_area(x0, y0, z0, x1, y1, z1);
116612
116195
  }
@@ -118874,7 +118457,6 @@ class CachingTextureAtlas extends AbstractTextureAtlas {
118874
118457
  /**
118875
118458
  *
118876
118459
  * @param {AbstractTextureAtlas} atlas
118877
- * @param {number} cache_size
118878
118460
  */
118879
118461
  constructor({
118880
118462
  atlas
@@ -119189,7 +118771,7 @@ class AbstractLight {
119189
118771
 
119190
118772
  /**
119191
118773
  *
119192
- * @param {AABB3} result
118774
+ * @param {number[]|ArrayLike<number>|Float32Array} result
119193
118775
  * @returns {void}
119194
118776
  */
119195
118777
  getAABB(result) {
@@ -119314,7 +118896,6 @@ function aabb3_matrix4_project_by_corners(result, aabb_corners, projection_matri
119314
118896
  }
119315
118897
 
119316
118898
  const corners = [];
119317
- const aabb_array = new Float32Array(6);
119318
118899
 
119319
118900
  class Decal extends AbstractLight {
119320
118901
  constructor() {
@@ -119346,7 +118927,7 @@ class Decal extends AbstractLight {
119346
118927
 
119347
118928
  /**
119348
118929
  *
119349
- * @param {number[]} m
118930
+ * @param {number[]|Float32Array|ArrayLike<number>} m
119350
118931
  */
119351
118932
  setTransform(m) {
119352
118933
  copy(this.transform, m);
@@ -119397,9 +118978,7 @@ class Decal extends AbstractLight {
119397
118978
  getAABB(result) {
119398
118979
  aabb3_build_corners(corners, 0, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5);
119399
118980
 
119400
- aabb3_matrix4_project_by_corners(aabb_array, corners, this.transform);
119401
-
119402
- result.readFromArray(aabb_array, 0);
118981
+ aabb3_matrix4_project_by_corners(result, corners, this.transform);
119403
118982
  }
119404
118983
 
119405
118984
  toArray(destination, address) {
@@ -119555,16 +119134,6 @@ function v3_distance(x0, y0, z0, x1, y1, z1) {
119555
119134
  return Math.sqrt(v3_distance_sqr(x0, y0, z0, x1, y1, z1));
119556
119135
  }
119557
119136
 
119558
- /**
119559
- *
119560
- * @param {{id:number}} a
119561
- * @param {{id:number}} b
119562
- * @returns {number}
119563
- */
119564
- function compareObjectsByNumericId(a,b){
119565
- return a.id - b.id;
119566
- }
119567
-
119568
119137
  /**
119569
119138
  * TODO compute slices to minimize world-space volume difference between clusters
119570
119139
  * @param {number[]} input_frustum_corners corners of input frustum
@@ -119718,6 +119287,240 @@ function read_cluster_frustum_corners(output, i_z_0, tr_xy_1, i_y_0, tr_x_1, i_x
119718
119287
  read_frustum_corner(cluster_frustum_points, frustum_point_index_111, output, 21);
119719
119288
  }
119720
119289
 
119290
+ const _lut_array_buffer = new ArrayBuffer(84);
119291
+ /**
119292
+ * Mapping from 3 plane bitfield, corresponding to intersection point of the planes
119293
+ * @type {number[]}
119294
+ */
119295
+ const triplanar_corner_mapping = new Uint8Array(_lut_array_buffer, 0, 43);
119296
+
119297
+ triplanar_corner_mapping[0b010101] = 0;
119298
+ triplanar_corner_mapping[0b100101] = 1;
119299
+ triplanar_corner_mapping[0b011001] = 2;
119300
+ triplanar_corner_mapping[0b101001] = 3;
119301
+ triplanar_corner_mapping[0b010110] = 4;
119302
+ triplanar_corner_mapping[0b100110] = 5;
119303
+ triplanar_corner_mapping[0b011010] = 6;
119304
+ triplanar_corner_mapping[0b101010] = 7;
119305
+ /**
119306
+ * Mapping from 2 plane bitfield to 2 corner bitfield, corresponding to corner indices of intersecting planes
119307
+ * @type {number[]}
119308
+ */
119309
+ const biplanar_edge_mapping = new Uint8Array(_lut_array_buffer, 43, 41);
119310
+
119311
+ biplanar_edge_mapping[0b000101] = 0 | (1 << 3);
119312
+ biplanar_edge_mapping[0b000110] = 4 | (5 << 3);
119313
+
119314
+ biplanar_edge_mapping[0b001001] = 2 | (3 << 3);
119315
+ biplanar_edge_mapping[0b001010] = 6 | (7 << 3);
119316
+
119317
+ biplanar_edge_mapping[0b010100] = 0 | (4 << 3);
119318
+ biplanar_edge_mapping[0b011000] = 2 | (6 << 3);
119319
+
119320
+ biplanar_edge_mapping[0b100100] = 1 | (5 << 3);
119321
+ biplanar_edge_mapping[0b101000] = 3 | (7 << 3);
119322
+
119323
+ biplanar_edge_mapping[0b010001] = 0 | (2 << 3);
119324
+ biplanar_edge_mapping[0b010010] = 4 | (6 << 3);
119325
+
119326
+ biplanar_edge_mapping[0b100001] = 1 | (3 << 3);
119327
+ biplanar_edge_mapping[0b100010] = 5 | (7 << 3);
119328
+
119329
+ /**
119330
+ * Computes shortest distance between a line segment(defined by 2 points) and a point
119331
+ * @param {number} x0
119332
+ * @param {number} y0
119333
+ * @param {number} z0
119334
+ * @param {number} x1
119335
+ * @param {number} y1
119336
+ * @param {number} z1
119337
+ * @param {number} px
119338
+ * @param {number} py
119339
+ * @param {number} pz
119340
+ */
119341
+ function line3_computeSegmentPointDistance_sqr(x0, y0, z0, x1, y1, z1, px, py, pz) {
119342
+ // get line delta
119343
+ const line_delta_x = x1 - x0;
119344
+ const line_delta_y = y1 - y0;
119345
+ const line_delta_z = z1 - z0;
119346
+
119347
+ // find closest point
119348
+ const sp0_x = px - x0;
119349
+ const sp0_y = py - y0;
119350
+ const sp0_z = pz - z0;
119351
+
119352
+ //
119353
+ const d2 = line_delta_x * line_delta_x + line_delta_y * line_delta_y + line_delta_z * line_delta_z;
119354
+
119355
+ const d3 = line_delta_x * sp0_x + line_delta_y * sp0_y + line_delta_z * sp0_z;
119356
+
119357
+ const t = clamp01(d3 / d2);
119358
+
119359
+ // compute point on the line
119360
+ const lp_x = line_delta_x * t + x0;
119361
+ const lp_y = line_delta_y * t + y0;
119362
+ const lp_z = line_delta_z * t + z0;
119363
+
119364
+ // compute distance from the point in question to the point on the line
119365
+ return v3_distance_sqr(px, py, pz, lp_x, lp_y, lp_z);
119366
+ }
119367
+
119368
+ /**
119369
+ *
119370
+ * @param {number} radius
119371
+ * @param {number} light_x
119372
+ * @param {number} light_y
119373
+ * @param {number} light_z
119374
+ * @param {number} outside_plane_count
119375
+ * @param {number} outside_plane_bitfield
119376
+ * @param {number[]} points
119377
+ * @return {boolean}
119378
+ */
119379
+ function detailed_sphere_frustum_intersection_test(
119380
+ radius, light_x, light_y, light_z,
119381
+ outside_plane_count, outside_plane_bitfield,
119382
+ points
119383
+ ) {
119384
+
119385
+ const radius_sqr = radius * radius;
119386
+
119387
+ if (outside_plane_count === 3) {
119388
+ // nearest point in a corner, find the corner
119389
+ const point_index = triplanar_corner_mapping[outside_plane_bitfield];
119390
+
119391
+ const point_address = point_index * 3;
119392
+
119393
+ const point_x = points[point_address];
119394
+ const point_y = points[point_address + 1];
119395
+ const point_z = points[point_address + 2];
119396
+
119397
+ const distance_to_light_sqr = v3_distance_sqr(
119398
+ point_x, point_y, point_z,
119399
+ light_x, light_y, light_z
119400
+ );
119401
+
119402
+ // query_bvh_frustum_from_objects.checks_sphere_frustum_corner++;
119403
+
119404
+ // return distance_to_light_sqr <= radius_sqr;
119405
+
119406
+ if (distance_to_light_sqr > radius_sqr) {
119407
+
119408
+ // query_bvh_frustum_from_objects.rejection_sphere_count++;
119409
+ return false;
119410
+ }
119411
+
119412
+ } else if (outside_plane_count === 2) {
119413
+ // nearest point is on an edge of two plane intersection
119414
+ const edge_bitfield = biplanar_edge_mapping[outside_plane_bitfield];
119415
+
119416
+ // get 2 corners from edge bitfield
119417
+ const corner_index_0 = edge_bitfield & 0b111;
119418
+ const corner_address_0 = corner_index_0 * 3;
119419
+
119420
+ const corner_index_1 = (edge_bitfield >> 3) & 0b111;
119421
+ const corner_address_1 = corner_index_1 * 3;
119422
+
119423
+ const point_0_x = points[corner_address_0];
119424
+ const point_0_y = points[corner_address_0 + 1];
119425
+ const point_0_z = points[corner_address_0 + 2];
119426
+
119427
+ const point_1_x = points[corner_address_1];
119428
+ const point_1_y = points[corner_address_1 + 1];
119429
+ const point_1_z = points[corner_address_1 + 2];
119430
+
119431
+ const distance_to_frustum_sqr = line3_computeSegmentPointDistance_sqr(
119432
+ point_0_x, point_0_y, point_0_z,
119433
+ point_1_x, point_1_y, point_1_z,
119434
+ light_x, light_y, light_z
119435
+ );
119436
+
119437
+ // query_bvh_frustum_from_objects.checks_sphere_frustum_edge++;
119438
+
119439
+ // return distance_to_frustum_sqr <= radius_sqr;
119440
+
119441
+ if (distance_to_frustum_sqr > radius_sqr) {
119442
+
119443
+ // query_bvh_frustum_from_objects.rejection_sphere_count++;
119444
+ return false;
119445
+ }
119446
+ }
119447
+
119448
+ return true;
119449
+ }
119450
+
119451
+ /**
119452
+ *
119453
+ * @param {number} light_x
119454
+ * @param {number} light_y
119455
+ * @param {number} light_z
119456
+ * @param {number} radius
119457
+ * @param {number[]|Float32Array} points
119458
+ * @param {number[]|Float32Array|Float64Array} planes
119459
+ * @returns {boolean}
119460
+ */
119461
+ function point_light_inside_volume(
119462
+ light_x, light_y, light_z, radius,
119463
+ points, planes
119464
+ ) {
119465
+ let j = 0;
119466
+ let outside_plane_count = 0;
119467
+ let outside_plane_bitfield = 0;
119468
+
119469
+ // validate if the sphere intersects the plane-bound space
119470
+
119471
+ // query_bvh_frustum_from_objects.checks_sphere++;
119472
+
119473
+ for (; j < 6; j++) {
119474
+
119475
+ const plane_address = j * 4;
119476
+
119477
+ const plane_normal_x = planes[plane_address];
119478
+ const plane_normal_y = planes[plane_address + 1];
119479
+ const plane_normal_z = planes[plane_address + 2];
119480
+ const plane_constant = planes[plane_address + 3];
119481
+
119482
+ /*
119483
+ compute distance from the center of the sphere to the plane
119484
+ NOTE: inlined computation of distance from point to plane
119485
+ */
119486
+ const distance = (plane_normal_x * light_x + plane_normal_y * light_y + plane_normal_z * light_z) + plane_constant;
119487
+
119488
+ // query_bvh_frustum_from_objects.checks_sphere_plane++;
119489
+
119490
+ if (distance < 0) {
119491
+ // center of the sphere is below the plane
119492
+
119493
+ if (distance >= -radius) {
119494
+
119495
+ // sphere intersects the plane
119496
+
119497
+ outside_plane_count++;
119498
+
119499
+ const plane_bit_mask = 1 << j;
119500
+
119501
+ outside_plane_bitfield |= plane_bit_mask;
119502
+ } else {
119503
+ // sphere is entirely below the plane
119504
+
119505
+ // query_bvh_frustum_from_objects.rejection_sphere_count++;
119506
+
119507
+ return false;
119508
+ }
119509
+ }
119510
+
119511
+ }
119512
+
119513
+ if (outside_plane_count < 2) {
119514
+ return true;
119515
+ } else {
119516
+ return detailed_sphere_frustum_intersection_test(
119517
+ radius, light_x, light_y, light_z,
119518
+ outside_plane_count, outside_plane_bitfield,
119519
+ points
119520
+ );
119521
+ }
119522
+ }
119523
+
119721
119524
  /**
119722
119525
  *
119723
119526
  * @type {number[]}
@@ -120076,7 +119879,7 @@ function encode_light_descriptor(address, light) {
120076
119879
 
120077
119880
  /**
120078
119881
  *
120079
- * @param {IncrementalDeltaSet<PointLightData>} data_set
119882
+ * @param {IncrementalDeltaSet<LightRenderMetadata>} data_set
120080
119883
  * @param {BinaryUint32BVH} bvh
120081
119884
  */
120082
119885
  function build_light_data_bvh(data_set, bvh) {
@@ -120090,18 +119893,18 @@ function build_light_data_bvh(data_set, bvh) {
120090
119893
 
120091
119894
  /**
120092
119895
  *
120093
- * @type {PointLightData}
119896
+ * @type {LightRenderMetadata}
120094
119897
  */
120095
119898
  const datum = elements[i];
120096
119899
 
120097
- const bb = datum.bvh_leaf_main;
119900
+ const bb = datum.bvh_leaf.bounds;
120098
119901
 
120099
119902
  const payload = encode_light_descriptor(datum.address, datum.light);
120100
119903
 
120101
119904
  bvh.setLeafData(
120102
119905
  i, payload,
120103
- bb.x0, bb.y0, bb.z0,
120104
- bb.x1, bb.y1, bb.z1
119906
+ bb[0], bb[1], bb[2],
119907
+ bb[3], bb[4], bb[5],
120105
119908
  );
120106
119909
  }
120107
119910
 
@@ -120111,22 +119914,32 @@ function build_light_data_bvh(data_set, bvh) {
120111
119914
  bvh.build();
120112
119915
  }
120113
119916
 
119917
+ /**
119918
+ *
119919
+ * @param {LightRenderMetadata} a
119920
+ * @param {LightRenderMetadata} b
119921
+ * @returns {number}
119922
+ */
119923
+ function compareLRMByLightId(a, b) {
119924
+ return b.light.id - a.light.id;
119925
+ }
119926
+
120114
119927
  class LightManager {
120115
119928
 
120116
- constructor() {
119929
+ /**
119930
+ * @readonly
119931
+ * @type {ExplicitBinaryBoundingVolumeHierarchy}
119932
+ */
119933
+ #light_data_bvh = new ExplicitBinaryBoundingVolumeHierarchy();
120117
119934
 
120118
- /**
120119
- * @type {BinaryNode<PointLightData>}
120120
- * @private
120121
- */
120122
- this.__light_data_bvh = new BinaryNode();
119935
+ /**
119936
+ * Mapping from a light/decal object ID internal metadata
119937
+ * @type {Map<number,LightRenderMetadata>}
119938
+ */
119939
+ #metadata_map = new Map();
120123
119940
 
120124
- /**
120125
- *
120126
- * @type {Map<AbstractLight, PointLightData>}
120127
- * @private
120128
- */
120129
- this.__light_data_map = new Map();
119941
+
119942
+ constructor() {
120130
119943
 
120131
119944
  /**
120132
119945
  * Number of cluster slices along each dimension
@@ -120229,22 +120042,22 @@ class LightManager {
120229
120042
 
120230
120043
  /**
120231
120044
  *
120232
- * @type {IncrementalDeltaSet<PointLightData>}
120045
+ * @type {IncrementalDeltaSet<LightRenderMetadata>}
120233
120046
  * @readonly
120234
120047
  * @private
120235
120048
  */
120236
- this.__visible_lights = new IncrementalDeltaSet(compareObjectsByNumericId);
120049
+ this.__visible_lights = new IncrementalDeltaSet(compareLRMByLightId);
120237
120050
  /**
120238
120051
  *
120239
- * @type {IncrementalDeltaSet<PointLightData>}
120052
+ * @type {IncrementalDeltaSet<LightRenderMetadata>}
120240
120053
  * @readonly
120241
120054
  * @private
120242
120055
  */
120243
- this.__visible_decals = new IncrementalDeltaSet(compareObjectsByNumericId);
120056
+ this.__visible_decals = new IncrementalDeltaSet(compareLRMByLightId);
120244
120057
 
120245
120058
  /**
120246
120059
  *
120247
- * @type {PointLightData[]}
120060
+ * @type {LightRenderMetadata[]}
120248
120061
  * @private
120249
120062
  */
120250
120063
  this.__sorted_visible_lights = [];
@@ -120481,7 +120294,7 @@ class LightManager {
120481
120294
 
120482
120295
  /**
120483
120296
  *
120484
- * @param {PointLightData} data
120297
+ * @param {LightRenderMetadata} data
120485
120298
  * @private
120486
120299
  */
120487
120300
  __handle_visible_decal_added(data) {
@@ -120513,7 +120326,7 @@ class LightManager {
120513
120326
 
120514
120327
  /**
120515
120328
  *
120516
- * @param {PointLightData} data
120329
+ * @param {LightRenderMetadata} data
120517
120330
  * @private
120518
120331
  */
120519
120332
  __handle_visible_decal_removed(data) {
@@ -120550,7 +120363,7 @@ class LightManager {
120550
120363
 
120551
120364
  /**
120552
120365
  *
120553
- * @param {PointLightData} data
120366
+ * @param {LightRenderMetadata} data
120554
120367
  * @private
120555
120368
  */
120556
120369
  __handle_visible_light_added(data) {
@@ -120563,7 +120376,7 @@ class LightManager {
120563
120376
 
120564
120377
  /**
120565
120378
  *
120566
- * @param {PointLightData} data
120379
+ * @param {LightRenderMetadata} data
120567
120380
  * @private
120568
120381
  */
120569
120382
  __handle_visible_light_removed(data) {
@@ -120575,7 +120388,7 @@ class LightManager {
120575
120388
 
120576
120389
  /**
120577
120390
  *
120578
- * @param {PointLightData} light
120391
+ * @param {LightRenderMetadata} light
120579
120392
  * @returns {number}
120580
120393
  * @protected
120581
120394
  */
@@ -120593,7 +120406,7 @@ class LightManager {
120593
120406
 
120594
120407
  /**
120595
120408
  * DEBUG method
120596
- * @param {PointLightData} lights
120409
+ * @param {LightRenderMetadata} lights
120597
120410
  * @param {number} count
120598
120411
  * @returns {number} lower = better sorting score
120599
120412
  * @private
@@ -120690,7 +120503,7 @@ class LightManager {
120690
120503
 
120691
120504
  /**
120692
120505
  *
120693
- * @type {IncrementalDeltaSet<PointLightData>}
120506
+ * @type {IncrementalDeltaSet<LightRenderMetadata>}
120694
120507
  */
120695
120508
  const visible_lights = this.__visible_lights;
120696
120509
 
@@ -120704,20 +120517,54 @@ class LightManager {
120704
120517
 
120705
120518
  read_frustum_planes_to_array(this.__view_frustum.planes, scratch_frustum_planes);
120706
120519
 
120707
- const match_count = query_bvh_frustum_from_objects(nodes, 0, this.__light_data_bvh, scratch_frustum_planes, this.__view_frustum_points);
120520
+ /*
120521
+ Search is done in 2 phases:
120522
+ 1) broad phase using bounding boxes
120523
+ 2) granular phase where we use object-specific shape to check against frustum
120524
+ */
120525
+
120526
+ const broad_match_count = bvh_query_user_data_overlaps_frustum(nodes, 0, this.#light_data_bvh, scratch_frustum_planes);
120527
+
120528
+ for (let i = 0; i < broad_match_count; i++) {
120708
120529
 
120709
- for (let i = 0; i < match_count; i++) {
120530
+ const light_id = nodes[i];
120710
120531
 
120711
120532
  /**
120712
120533
  *
120713
- * @type {PointLightData}
120534
+ * @type {LightRenderMetadata}
120714
120535
  */
120715
- const light_data = nodes[i];
120536
+ const light_data = this.#metadata_map.get(light_id);
120537
+
120538
+ /**
120539
+ *
120540
+ * @type {PointLight|Decal}
120541
+ */
120542
+ const light = light_data.light;
120543
+
120544
+ if (light.isDecal === true) {
120545
+
120716
120546
 
120717
- if (light_data.light instanceof Decal) {
120718
120547
  // decals go into a separate bucket
120719
120548
  visible_decals.push(light_data);
120720
- } else {
120549
+
120550
+ } else if (light.isPointLight === true) {
120551
+ // perform granular check
120552
+
120553
+ const light_position = light.position;
120554
+
120555
+ const light_x = light_position.x;
120556
+ const light_y = light_position.y;
120557
+ const light_z = light_position.z;
120558
+
120559
+ const radius = light.radius.getValue();
120560
+
120561
+ if (!point_light_inside_volume(light_x, light_y, light_z, radius, this.__view_frustum_points, scratch_frustum_planes)) {
120562
+ // outside of view frustum
120563
+ continue;
120564
+ }
120565
+
120566
+
120567
+ // register as visible
120721
120568
  visible_lights.push(light_data);
120722
120569
  }
120723
120570
 
@@ -120732,7 +120579,7 @@ class LightManager {
120732
120579
 
120733
120580
  /**
120734
120581
  *
120735
- * @type {PointLightData[]}
120582
+ * @type {LightRenderMetadata[]}
120736
120583
  */
120737
120584
  const visible_lights = this.__sorted_visible_lights;
120738
120585
 
@@ -121076,17 +120923,17 @@ class LightManager {
121076
120923
  * @param {number} z
121077
120924
  */
121078
120925
  setTileMapResolution(x, y, z) {
121079
- assert.isNumber(x,'x');
121080
- assert.isNonNegativeInteger(x,'x');
121081
- assert.isFiniteNumber(x,'x');
120926
+ assert.isNumber(x, 'x');
120927
+ assert.isNonNegativeInteger(x, 'x');
120928
+ assert.isFiniteNumber(x, 'x');
121082
120929
 
121083
- assert.isNumber(y,'y');
121084
- assert.isNonNegativeInteger(y,'y');
121085
- assert.isFiniteNumber(y,'y');
120930
+ assert.isNumber(y, 'y');
120931
+ assert.isNonNegativeInteger(y, 'y');
120932
+ assert.isFiniteNumber(y, 'y');
121086
120933
 
121087
- assert.isNumber(z,'z');
121088
- assert.isNonNegativeInteger(z,'z');
121089
- assert.isFiniteNumber(z,'z');
120934
+ assert.isNumber(z, 'z');
120935
+ assert.isNonNegativeInteger(z, 'z');
120936
+ assert.isFiniteNumber(z, 'z');
121090
120937
 
121091
120938
  const r = this.__tiles_resolution;
121092
120939
 
@@ -121120,13 +120967,11 @@ class LightManager {
121120
120967
  * @param {AbstractLight} light
121121
120968
  */
121122
120969
  addLight(light) {
121123
- const lightData = new PointLightData(light);
121124
-
121125
- lightData.link();
120970
+ const lightData = new LightRenderMetadata(light);
121126
120971
 
121127
- this.__light_data_bvh.insertNode(lightData.bvh_leaf_main);
120972
+ lightData.link(this.#light_data_bvh);
121128
120973
 
121129
- this.__light_data_map.set(light, lightData);
120974
+ this.#metadata_map.set(light.id, lightData);
121130
120975
  }
121131
120976
 
121132
120977
  /**
@@ -121136,7 +120981,9 @@ class LightManager {
121136
120981
  */
121137
120982
  removeLight(light) {
121138
120983
 
121139
- const data = this.__light_data_map.get(light);
120984
+ const light_id = light.id;
120985
+
120986
+ const data = this.#metadata_map.get(light_id);
121140
120987
 
121141
120988
  if (data === undefined) {
121142
120989
  return false;
@@ -121144,7 +120991,7 @@ class LightManager {
121144
120991
 
121145
120992
  data.unlink();
121146
120993
 
121147
- this.__light_data_map.delete(light);
120994
+ this.#metadata_map.delete(light_id);
121148
120995
 
121149
120996
  return true;
121150
120997
  }
@@ -121773,6 +121620,7 @@ class ForwardPlusRenderingPlugin extends EnginePlugin {
121773
121620
  getLightManager() {
121774
121621
  return this.__light_manager;
121775
121622
  }
121623
+
121776
121624
  }
121777
121625
 
121778
121626
  /**
@@ -122410,10 +122258,6 @@ class PointLight extends AbstractLight {
122410
122258
  this.position.writeToArray(result, 0);
122411
122259
  }
122412
122260
 
122413
- /**
122414
- *
122415
- * @param {AABB3} result
122416
- */
122417
122261
  getAABB(result) {
122418
122262
  const r = this.radius.getValue();
122419
122263
  const p = this.position;
@@ -122422,15 +122266,13 @@ class PointLight extends AbstractLight {
122422
122266
  const center_y = p.y;
122423
122267
  const center_z = p.z;
122424
122268
 
122425
- result.setBounds(
122426
- center_x - r,
122427
- center_y - r,
122428
- center_z - r,
122269
+ result[0] = center_x - r;
122270
+ result[1] = center_y - r;
122271
+ result[2] = center_z - r;
122429
122272
 
122430
- center_x + r,
122431
- center_y + r,
122432
- center_z + r
122433
- );
122273
+ result[3] = center_x + r;
122274
+ result[4] = center_y + r;
122275
+ result[5] = center_z + r;
122434
122276
  }
122435
122277
 
122436
122278
  onDimensionChanged(listener, context) {
@@ -124891,6 +124733,12 @@ function browserInfo() {
124891
124733
  return cached;
124892
124734
  }
124893
124735
 
124736
+ const navigator = globalThis.navigator;
124737
+
124738
+ if(navigator === undefined){
124739
+ throw new Error('Not a browser, globalThis.navigator is undefined');
124740
+ }
124741
+
124894
124742
  let ua = navigator.userAgent, tem,
124895
124743
  M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
124896
124744
 
@@ -125114,7 +124962,7 @@ function setListenerPositionNOOP(listener, position) {
125114
124962
 
125115
124963
  let setListenerPosition = setListenerPositionNOOP;
125116
124964
 
125117
- if (navigator !== undefined) {
124965
+ if (globalThis.navigator !== undefined) {
125118
124966
  const info = browserInfo();
125119
124967
  if (info.name === "Chrome") {
125120
124968
  if (info.version >= 64) {
@@ -125166,7 +125014,7 @@ function setListenerOrientation2(listener, forward, up) {
125166
125014
 
125167
125015
  let setListenerOrientation = noop;
125168
125016
 
125169
- if (navigator !== undefined) {
125017
+ if (globalThis.navigator !== undefined) {
125170
125018
  const info = browserInfo();
125171
125019
  if (info.name === "Chrome") {
125172
125020
  setListenerOrientation = setListenerOrientation1;
@@ -125926,6 +125774,9 @@ const ParallelBehaviorPolicy = {
125926
125774
  RequireAll: 1
125927
125775
  };
125928
125776
 
125777
+ /**
125778
+ * Executes all contained behaviors in parallel
125779
+ */
125929
125780
  class ParallelBehavior extends CompositeBehavior {
125930
125781
  /**
125931
125782
  *
@@ -125935,6 +125786,9 @@ class ParallelBehavior extends CompositeBehavior {
125935
125786
  constructor(successPolicy, failurePolicy) {
125936
125787
  super();
125937
125788
 
125789
+ assert.enum(successPolicy, ParallelBehaviorPolicy, 'successPolicy');
125790
+ assert.enum(failurePolicy, ParallelBehaviorPolicy, 'failurePolicy');
125791
+
125938
125792
  /**
125939
125793
  * @private
125940
125794
  * @type {ParallelBehaviorPolicy}
@@ -125948,6 +125802,7 @@ class ParallelBehavior extends CompositeBehavior {
125948
125802
  this.failurePolicy = failurePolicy;
125949
125803
 
125950
125804
  /**
125805
+ * @readonly
125951
125806
  * @private
125952
125807
  * @type {BitSet}
125953
125808
  */
@@ -125975,10 +125830,11 @@ class ParallelBehavior extends CompositeBehavior {
125975
125830
 
125976
125831
  /**
125977
125832
  *
125978
- * @param {ParallelBehaviorPolicy|number} v
125833
+ * @param {ParallelBehaviorPolicy|number} policy
125979
125834
  */
125980
- setSuccessPolicy(v) {
125981
- this.successPolicy = v;
125835
+ setSuccessPolicy(policy) {
125836
+ assert.enum(policy, ParallelBehaviorPolicy, 'policy');
125837
+ this.successPolicy = policy;
125982
125838
  }
125983
125839
 
125984
125840
  /**
@@ -125991,10 +125847,11 @@ class ParallelBehavior extends CompositeBehavior {
125991
125847
 
125992
125848
  /**
125993
125849
  *
125994
- * @param {ParallelBehaviorPolicy|number} v
125850
+ * @param {ParallelBehaviorPolicy|number} policy
125995
125851
  */
125996
- setFailurePolicy(v) {
125997
- this.failurePolicy = v;
125852
+ setFailurePolicy(policy) {
125853
+ assert.enum(policy, ParallelBehaviorPolicy, 'policy');
125854
+ this.failurePolicy = policy;
125998
125855
  }
125999
125856
 
126000
125857
  /**
@@ -126128,14 +125985,16 @@ class ParallelBehavior extends CompositeBehavior {
126128
125985
  /**
126129
125986
  *
126130
125987
  * @param {Behavior[]} elements
126131
- * @param {ParallelBehaviorPolicy} success
126132
- * @param {ParallelBehaviorPolicy} failure
125988
+ * @param {ParallelBehaviorPolicy} success how should successful completion be determined?
125989
+ * @param {ParallelBehaviorPolicy} failure how should failing completion be determined
126133
125990
  * @returns {ParallelBehavior}
126134
125991
  */
126135
125992
  static from(elements, success = ParallelBehaviorPolicy.RequireAll, failure = ParallelBehaviorPolicy.RequireOne) {
125993
+ assert.isArray(elements, 'elements');
125994
+
126136
125995
  const r = new ParallelBehavior(success, failure);
126137
125996
 
126138
- elements.forEach(e => r.addChild(e));
125997
+ r.addChildren(elements);
126139
125998
 
126140
125999
  return r;
126141
126000
  }