@woosh/meep-engine 2.36.10 → 2.36.13

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.
@@ -1,24 +1,19 @@
1
- import { RowFirstTable } from "../../collection/table/RowFirstTable.js";
2
- import { RowFirstTableSpec } from "../../collection/table/RowFirstTableSpec.js";
3
- import { DataType } from "../../collection/table/DataType.js";
4
1
  import { aabb3_compute_surface_area } from "../aabb3/aabb3_compute_surface_area.js";
5
2
  import { min2 } from "../../math/min2.js";
6
3
  import { max2 } from "../../math/max2.js";
7
4
  import { assert } from "../../assert.js";
8
5
 
9
- const TABLE_SPEC = RowFirstTableSpec.get([
10
- DataType.Float32, DataType.Float32, DataType.Float32, // x0, y0, z0
11
- DataType.Float32, DataType.Float32, DataType.Float32, // x1, y1, z1
12
- DataType.Uint32, // parent
13
- DataType.Uint32, // child-1
14
- DataType.Uint32, // child-2 / user-data (dual use)
15
- DataType.Uint16 // height + flags
16
- ]);
17
-
18
6
  const COLUMN_PARENT = 6;
19
7
  const COLUMN_CHILD_1 = 7;
20
8
  const COLUMN_CHILD_2 = 8;
21
9
  const COLUMN_HEIGHT = 9;
10
+
11
+ /**
12
+ * A non-leaf node have both CHILD_1 and CHILD_2 set, when CHILD_1 is not set - it's a leaf node
13
+ * So we can utilize space of CHILD_2 to store USER_DATA, hence there is overlap in schema
14
+ * @readonly
15
+ * @type {number}
16
+ */
22
17
  const COLUMN_USER_DATA = COLUMN_CHILD_2;
23
18
 
24
19
  /**
@@ -26,34 +21,61 @@ const COLUMN_USER_DATA = COLUMN_CHILD_2;
26
21
  * @type {number}
27
22
  */
28
23
  export const NULL_NODE = 4294967295;
24
+
29
25
  /**
30
- *
26
+ * @readonly
27
+ * @type {number}
28
+ */
29
+ const CAPACITY_GROW_MULTIPLIER = 1.2;
30
+
31
+ /**
32
+ * @readonly
31
33
  * @type {number}
32
34
  */
33
- export const NULL_USER_DATA = NULL_NODE;
35
+ const CAPACITY_GROW_MIN_STEP = 64;
34
36
 
35
37
  /**
36
38
  * @readonly
37
- * @type {number[]}
39
+ * @type {number}
38
40
  */
39
- const DEFAULT_ROW_VALUE = Object.freeze([
40
- Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY,
41
- Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY,
42
- NULL_NODE, // parent
43
- NULL_NODE, // child-1
44
- NULL_NODE, // child-2 / user-data
45
- 0 // height
46
- ]);
41
+ const ELEMENT_WORD_COUNT = 10;
47
42
 
48
43
  export class ExplicitBinaryBoundingVolumeHierarchy {
49
44
  constructor() {
45
+ /**
46
+ *
47
+ * @type {ArrayBuffer}
48
+ * @private
49
+ */
50
+ this.__data_buffer = new ArrayBuffer(0);
51
+
52
+ /**
53
+ *
54
+ * @type {Float32Array}
55
+ * @private
56
+ */
57
+ this.__data_float32 = new Float32Array(this.__data_buffer);
58
+
59
+ /**
60
+ *
61
+ * @type {Uint32Array}
62
+ * @private
63
+ */
64
+ this.__data_uint32 = new Uint32Array(this.__data_buffer);
65
+
66
+ /**
67
+ *
68
+ * @type {number}
69
+ * @private
70
+ */
71
+ this.__capacity = 0;
50
72
 
51
73
  /**
52
74
  *
53
- * @type {RowFirstTable}
75
+ * @type {number}
54
76
  * @private
55
77
  */
56
- this.__data = new RowFirstTable(TABLE_SPEC);
78
+ this.__size = 0;
57
79
 
58
80
  /**
59
81
  *
@@ -70,14 +92,6 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
70
92
  this.__root = NULL_NODE;
71
93
  }
72
94
 
73
- /**
74
- *
75
- * @returns {RowFirstTable}
76
- */
77
- get data() {
78
- return this.__data;
79
- }
80
-
81
95
  /**
82
96
  *
83
97
  * @returns {number}
@@ -91,7 +105,28 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
91
105
  * @returns {number}
92
106
  */
93
107
  get node_capacity() {
94
- return this.__data.capacity;
108
+ return this.__capacity;
109
+ }
110
+
111
+ __grow_capacity() {
112
+ const new_capacity = Math.ceil(max2(
113
+ this.__capacity * CAPACITY_GROW_MULTIPLIER,
114
+ this.__capacity + CAPACITY_GROW_MIN_STEP
115
+ ));
116
+
117
+ const old_data_uint32 = this.__data_uint32;
118
+
119
+ const new_data_buffer = new ArrayBuffer(new_capacity * ELEMENT_WORD_COUNT * 4);
120
+
121
+ this.__data_buffer = new_data_buffer;
122
+
123
+ this.__data_float32 = new Float32Array(new_data_buffer);
124
+ this.__data_uint32 = new Uint32Array(new_data_buffer);
125
+
126
+ // copy old data into new buffer
127
+ this.__data_uint32.set(old_data_uint32);
128
+
129
+ this.__capacity = new_capacity;
95
130
  }
96
131
 
97
132
  /**
@@ -107,19 +142,39 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
107
142
  result = free.pop();
108
143
  } else {
109
144
 
110
- const data = this.__data;
111
-
112
- const n = data.length;
145
+ result = this.__size;
113
146
 
114
- data.resize(n + 1);
115
-
116
- data.length++;
147
+ if (result >= this.__capacity) {
148
+ // grow capacity
149
+ // console.log(`#GROW`);
150
+ this.__grow_capacity();
151
+ }
117
152
 
118
- result = n;
153
+ this.__size++;
119
154
  }
120
155
 
121
156
  // initialize node
122
- this.__data.setRow(result, DEFAULT_ROW_VALUE);
157
+
158
+ const address = ELEMENT_WORD_COUNT * result;
159
+
160
+ const float32 = this.__data_float32;
161
+
162
+ // write AABB
163
+ float32[address] = Number.POSITIVE_INFINITY;
164
+ float32[address + 1] = Number.POSITIVE_INFINITY;
165
+ float32[address + 2] = Number.POSITIVE_INFINITY;
166
+ float32[address + 3] = Number.NEGATIVE_INFINITY;
167
+ float32[address + 4] = Number.NEGATIVE_INFINITY;
168
+ float32[address + 5] = Number.NEGATIVE_INFINITY;
169
+
170
+ const uint32 = this.__data_uint32;
171
+
172
+ uint32[address + COLUMN_PARENT] = NULL_NODE; // parent
173
+ uint32[address + COLUMN_CHILD_1] = NULL_NODE; // child-1
174
+ uint32[address + COLUMN_CHILD_2] = NULL_NODE; // child-2 / user-data
175
+ uint32[address + COLUMN_HEIGHT] = 0; // height
176
+
177
+ // console.log(`#ALLOCATED: ${result}`);
123
178
 
124
179
  return result;
125
180
  }
@@ -130,8 +185,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
130
185
  */
131
186
  release_node(id) {
132
187
  assert.isNonNegativeInteger(id, 'id');
133
- // TODO reset node
134
-
188
+ // no reset required as that's handled in the allocation method
135
189
  this.__free.push(id);
136
190
  }
137
191
 
@@ -142,7 +196,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
142
196
  */
143
197
  node_is_leaf(id) {
144
198
  assert.isNonNegativeInteger(id, 'id');
145
- const child_1 = this.__data.readCellValue(id, COLUMN_CHILD_1);
199
+ const child_1 = this.__data_uint32[ELEMENT_WORD_COUNT * id + COLUMN_CHILD_1];
146
200
 
147
201
  return child_1 === NULL_NODE;
148
202
  }
@@ -154,7 +208,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
154
208
  */
155
209
  node_get_user_data(id) {
156
210
  assert.isNonNegativeInteger(id, 'id');
157
- return this.__data.readCellValue(id, COLUMN_USER_DATA);
211
+ return this.__data_uint32[ELEMENT_WORD_COUNT * id + COLUMN_USER_DATA];
158
212
  }
159
213
 
160
214
  /**
@@ -165,7 +219,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
165
219
  node_set_user_data(id, value) {
166
220
  assert.isNonNegativeInteger(id, 'id');
167
221
 
168
- this.__data.writeCellValue(id, COLUMN_USER_DATA, value);
222
+ this.__data_uint32[ELEMENT_WORD_COUNT * id + COLUMN_USER_DATA] = value;
169
223
  }
170
224
 
171
225
  /**
@@ -175,7 +229,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
175
229
  */
176
230
  node_get_child1(id) {
177
231
  assert.isNonNegativeInteger(id, 'id');
178
- return this.__data.readCellValue(id, COLUMN_CHILD_1);
232
+ return this.__data_uint32[ELEMENT_WORD_COUNT * id + COLUMN_CHILD_1];
179
233
  }
180
234
 
181
235
  /**
@@ -185,7 +239,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
185
239
  */
186
240
  node_get_child2(id) {
187
241
  assert.isNonNegativeInteger(id, 'id');
188
- return this.__data.readCellValue(id, COLUMN_CHILD_2);
242
+ return this.__data_uint32[ELEMENT_WORD_COUNT * id + COLUMN_CHILD_2];
189
243
  }
190
244
 
191
245
 
@@ -197,15 +251,16 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
197
251
  node_get_aabb(id, result) {
198
252
  assert.isNonNegativeInteger(id, 'id');
199
253
 
200
- const data = this.__data;
254
+ const address = ELEMENT_WORD_COUNT * id;
255
+ const float32 = this.__data_float32;
201
256
 
202
- result[0] = data.readCellValue(id, 0);
203
- result[1] = data.readCellValue(id, 1);
204
- result[2] = data.readCellValue(id, 2);
257
+ result[0] = float32[address];
258
+ result[1] = float32[address + 1];
259
+ result[2] = float32[address + 2];
205
260
 
206
- result[3] = data.readCellValue(id, 3);
207
- result[4] = data.readCellValue(id, 4);
208
- result[5] = data.readCellValue(id, 5);
261
+ result[3] = float32[address + 3];
262
+ result[4] = float32[address + 4];
263
+ result[5] = float32[address + 5];
209
264
  }
210
265
 
211
266
  /**
@@ -216,15 +271,16 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
216
271
  node_set_aabb(id, aabb) {
217
272
  assert.isNonNegativeInteger(id, 'id');
218
273
 
219
- const data = this.__data;
274
+ const address = ELEMENT_WORD_COUNT * id;
275
+ const float32 = this.__data_float32;
220
276
 
221
- data.writeCellValue(id, 0, aabb[0]);
222
- data.writeCellValue(id, 1, aabb[1]);
223
- data.writeCellValue(id, 2, aabb[2]);
277
+ float32[address] = aabb[0];
278
+ float32[address + 1] = aabb[1];
279
+ float32[address + 2] = aabb[2];
224
280
 
225
- data.writeCellValue(id, 3, aabb[3]);
226
- data.writeCellValue(id, 4, aabb[4]);
227
- data.writeCellValue(id, 5, aabb[5]);
281
+ float32[address + 3] = aabb[3];
282
+ float32[address + 4] = aabb[4];
283
+ float32[address + 5] = aabb[5];
228
284
  }
229
285
 
230
286
  /**
@@ -236,7 +292,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
236
292
  // TODO only refit for small changes, and re-insert for large changes
237
293
  this.node_set_aabb(id, aabb);
238
294
 
239
- const parent = this.__data.readCellValue(id, COLUMN_PARENT);
295
+ const parent = this.__data_uint32[ELEMENT_WORD_COUNT * id + COLUMN_PARENT];
240
296
 
241
297
  if (parent !== NULL_NODE) {
242
298
  this.bubble_up_refit(parent);
@@ -258,18 +314,18 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
258
314
  x0, y0, z0,
259
315
  x1, y1, z1
260
316
  ) {
261
-
262
317
  assert.isNonNegativeInteger(id, 'id');
263
318
 
264
- const data = this.__data;
319
+ const address = ELEMENT_WORD_COUNT * id;
320
+ const float32 = this.__data_float32;
265
321
 
266
- data.writeCellValue(id, 0, x0);
267
- data.writeCellValue(id, 1, y0);
268
- data.writeCellValue(id, 2, z0);
322
+ float32[address] = x0;
323
+ float32[address + 1] = y0;
324
+ float32[address + 2] = z0;
269
325
 
270
- data.writeCellValue(id, 3, x1);
271
- data.writeCellValue(id, 4, y1);
272
- data.writeCellValue(id, 5, z1);
326
+ float32[address + 3] = x1;
327
+ float32[address + 4] = y1;
328
+ float32[address + 5] = z1;
273
329
  }
274
330
 
275
331
  /**
@@ -280,15 +336,16 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
280
336
  node_get_surface_area(id) {
281
337
  assert.isNonNegativeInteger(id, 'id');
282
338
 
283
- const data = this.__data;
339
+ const address = ELEMENT_WORD_COUNT * id;
340
+ const float32 = this.__data_float32;
284
341
 
285
- const x0 = data.readCellValue(id, 0);
286
- const y0 = data.readCellValue(id, 1);
287
- const z0 = data.readCellValue(id, 2);
342
+ const x0 = float32[address];
343
+ const y0 = float32[address + 1];
344
+ const z0 = float32[address + 2];
288
345
 
289
- const x1 = data.readCellValue(id, 3);
290
- const y1 = data.readCellValue(id, 4);
291
- const z1 = data.readCellValue(id, 5);
346
+ const x1 = float32[address + 3];
347
+ const y1 = float32[address + 4];
348
+ const z1 = float32[address + 5];
292
349
 
293
350
  return aabb3_compute_surface_area(
294
351
  x0, y0, z0,
@@ -303,30 +360,33 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
303
360
  * @returns {number}
304
361
  */
305
362
  node_get_combined_surface_area(index_a, index_b) {
306
- const data = this.__data;
363
+ const address_a = ELEMENT_WORD_COUNT * index_a;
364
+ const address_b = ELEMENT_WORD_COUNT * index_b;
307
365
 
308
- const a_x0 = data.readCellValue(index_a, 0);
309
- const b_x0 = data.readCellValue(index_b, 0);
366
+ const float32 = this.__data_float32;
367
+
368
+ const a_x0 = float32[address_a];
369
+ const b_x0 = float32[address_b];
310
370
  const x0 = min2(a_x0, b_x0);
311
371
 
312
- const a_y0 = data.readCellValue(index_a, 1);
313
- const b_y0 = data.readCellValue(index_b, 1);
372
+ const a_y0 = float32[address_a + 1];
373
+ const b_y0 = float32[address_b + 1];
314
374
  const y0 = min2(a_y0, b_y0);
315
375
 
316
- const a_z0 = data.readCellValue(index_a, 2);
317
- const b_z0 = data.readCellValue(index_b, 2);
376
+ const a_z0 = float32[address_a + 2];
377
+ const b_z0 = float32[address_b + 2];
318
378
  const z0 = min2(a_z0, b_z0);
319
379
 
320
- const a_x1 = data.readCellValue(index_a, 3);
321
- const b_x1 = data.readCellValue(index_b, 3);
380
+ const a_x1 = float32[address_a + 3];
381
+ const b_x1 = float32[address_b + 3];
322
382
  const x1 = max2(a_x1, b_x1);
323
383
 
324
- const a_y1 = data.readCellValue(index_a, 4);
325
- const b_y1 = data.readCellValue(index_b, 4);
384
+ const a_y1 = float32[address_a + 4];
385
+ const b_y1 = float32[address_b + 4];
326
386
  const y1 = max2(a_y1, b_y1);
327
387
 
328
- const a_z1 = data.readCellValue(index_a, 5);
329
- const b_z1 = data.readCellValue(index_b, 5);
388
+ const a_z1 = float32[address_a + 5];
389
+ const b_z1 = float32[address_b + 5];
330
390
  const z1 = max2(a_z1, b_z1);
331
391
 
332
392
  return aabb3_compute_surface_area(
@@ -342,40 +402,44 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
342
402
  * @param {number} index_b
343
403
  */
344
404
  node_set_combined_aabb(destination, index_a, index_b) {
405
+ const address_a = ELEMENT_WORD_COUNT * index_a;
406
+ const address_b = ELEMENT_WORD_COUNT * index_b;
345
407
 
346
- const data = this.__data;
408
+ const float32 = this.__data_float32;
347
409
 
348
- const a_x0 = data.readCellValue(index_a, 0);
349
- const b_x0 = data.readCellValue(index_b, 0);
410
+ const a_x0 = float32[address_a];
411
+ const b_x0 = float32[address_b];
350
412
  const x0 = min2(a_x0, b_x0);
351
413
 
352
- const a_y0 = data.readCellValue(index_a, 1);
353
- const b_y0 = data.readCellValue(index_b, 1);
414
+ const a_y0 = float32[address_a + 1];
415
+ const b_y0 = float32[address_b + 1];
354
416
  const y0 = min2(a_y0, b_y0);
355
417
 
356
- const a_z0 = data.readCellValue(index_a, 2);
357
- const b_z0 = data.readCellValue(index_b, 2);
418
+ const a_z0 = float32[address_a + 2];
419
+ const b_z0 = float32[address_b + 2];
358
420
  const z0 = min2(a_z0, b_z0);
359
421
 
360
- const a_x1 = data.readCellValue(index_a, 3);
361
- const b_x1 = data.readCellValue(index_b, 3);
422
+ const a_x1 = float32[address_a + 3];
423
+ const b_x1 = float32[address_b + 3];
362
424
  const x1 = max2(a_x1, b_x1);
363
425
 
364
- const a_y1 = data.readCellValue(index_a, 4);
365
- const b_y1 = data.readCellValue(index_b, 4);
426
+ const a_y1 = float32[address_a + 4];
427
+ const b_y1 = float32[address_b + 4];
366
428
  const y1 = max2(a_y1, b_y1);
367
429
 
368
- const a_z1 = data.readCellValue(index_a, 5);
369
- const b_z1 = data.readCellValue(index_b, 5);
430
+ const a_z1 = float32[address_a + 5];
431
+ const b_z1 = float32[address_b + 5];
370
432
  const z1 = max2(a_z1, b_z1);
371
433
 
372
- data.writeCellValue(destination, 0, x0);
373
- data.writeCellValue(destination, 1, y0);
374
- data.writeCellValue(destination, 2, z0);
434
+ const address_destination = destination * ELEMENT_WORD_COUNT;
435
+
436
+ float32[address_destination] = x0;
437
+ float32[address_destination + 1] = y0;
438
+ float32[address_destination + 2] = z0;
375
439
 
376
- data.writeCellValue(destination, 3, x1);
377
- data.writeCellValue(destination, 4, y1);
378
- data.writeCellValue(destination, 5, z1);
440
+ float32[address_destination + 3] = x1;
441
+ float32[address_destination + 4] = y1;
442
+ float32[address_destination + 5] = z1;
379
443
  }
380
444
 
381
445
  /**
@@ -386,13 +450,13 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
386
450
  insert_leaf(leaf) {
387
451
  assert.isNonNegativeInteger(leaf, 'leaf');
388
452
 
389
- const data = this.__data;
453
+ let uint32 = this.__data_uint32;
390
454
 
391
455
  if (this.__root === NULL_NODE) {
392
456
  // special case - no root, set this node as a root
393
457
  this.__root = leaf;
394
458
 
395
- data.writeCellValue(leaf, COLUMN_PARENT, NULL_NODE);
459
+ uint32[leaf * ELEMENT_WORD_COUNT + COLUMN_PARENT] = NULL_NODE;
396
460
 
397
461
  return;
398
462
  }
@@ -401,8 +465,8 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
401
465
  let index = this.__root;
402
466
 
403
467
  while (this.node_is_leaf(index) === false) {
404
- const child1 = data.readCellValue(index, COLUMN_CHILD_1);
405
- const child2 = data.readCellValue(index, COLUMN_CHILD_2);
468
+ const child1 = uint32[index * ELEMENT_WORD_COUNT + COLUMN_CHILD_1];
469
+ const child2 = uint32[index * ELEMENT_WORD_COUNT + COLUMN_CHILD_2];
406
470
 
407
471
  const area = this.node_get_surface_area(index);
408
472
 
@@ -451,22 +515,23 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
451
515
  const sibling = index;
452
516
 
453
517
  // Create a new parent.
454
- const oldParent = data.readCellValue(sibling, COLUMN_PARENT);
518
+ const oldParent = uint32[sibling * ELEMENT_WORD_COUNT + COLUMN_PARENT];
455
519
  const newParent = this.allocate_node();
456
520
 
457
- data.writeCellValue(newParent, COLUMN_PARENT, oldParent);
458
- data.writeCellValue(newParent, COLUMN_USER_DATA, NULL_USER_DATA);
521
+ uint32 = this.__data_uint32; // reference can be invalidated after allocation, re-bind
522
+
523
+ uint32[newParent * ELEMENT_WORD_COUNT + COLUMN_PARENT] = oldParent;
459
524
  this.node_set_combined_aabb(newParent, leaf, sibling);
460
- data.writeCellValue(newParent, COLUMN_HEIGHT,
461
- data.readCellValue(sibling, COLUMN_HEIGHT) + 1
462
- );
525
+ uint32[newParent * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = uint32[sibling * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] + 1;
463
526
 
464
527
  if (oldParent !== NULL_NODE) {
465
528
  // The sibling was not the root.
466
- if (data.readCellValue(oldParent, COLUMN_CHILD_1) === sibling) {
467
- data.writeCellValue(oldParent, COLUMN_CHILD_1, newParent);
529
+ if (uint32[oldParent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] === sibling) {
530
+ uint32[oldParent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] = newParent;
468
531
  } else {
469
- data.writeCellValue(oldParent, COLUMN_CHILD_2, newParent);
532
+ assert.equal(uint32[oldParent * ELEMENT_WORD_COUNT + COLUMN_CHILD_2], sibling);
533
+
534
+ uint32[oldParent * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = newParent;
470
535
  }
471
536
 
472
537
  } else {
@@ -474,15 +539,14 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
474
539
  this.__root = newParent;
475
540
  }
476
541
 
477
- data.writeCellValue(newParent, COLUMN_CHILD_1, sibling);
478
- data.writeCellValue(newParent, COLUMN_CHILD_2, leaf);
479
- data.writeCellValue(sibling, COLUMN_PARENT, newParent);
480
- data.writeCellValue(leaf, COLUMN_PARENT, newParent);
542
+ uint32[newParent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] = sibling;
543
+ uint32[newParent * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = leaf;
481
544
 
482
- // Walk back up the tree fixing heights and AABBs
483
- index = data.readCellValue(leaf, COLUMN_PARENT);
545
+ uint32[sibling * ELEMENT_WORD_COUNT + COLUMN_PARENT] = newParent;
546
+ uint32[leaf * ELEMENT_WORD_COUNT + COLUMN_PARENT] = newParent;
484
547
 
485
- this.bubble_up_update(index);
548
+ // Walk back up the tree fixing heights and AABBs
549
+ this.bubble_up_update(newParent);
486
550
 
487
551
  }
488
552
 
@@ -495,20 +559,20 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
495
559
  bubble_up_refit(parent) {
496
560
  let index = parent;
497
561
 
498
- const data = this.__data;
562
+ const uint32 = this.__data_uint32;
499
563
 
500
564
  while (index !== NULL_NODE) {
501
565
  index = this.balance(index);
502
566
 
503
- const child1 = data.readCellValue(index, COLUMN_CHILD_1);
504
- const child2 = data.readCellValue(index, COLUMN_CHILD_2);
567
+ const child1 = uint32[index * ELEMENT_WORD_COUNT + COLUMN_CHILD_1];
568
+ const child2 = uint32[index * ELEMENT_WORD_COUNT + COLUMN_CHILD_2];
505
569
 
506
570
  assert.notEqual(child1, NULL_NODE, 'child1 is null');
507
571
  assert.notEqual(child2, NULL_NODE, 'child2 is null');
508
572
 
509
573
  this.node_set_combined_aabb(index, child1, child2);
510
574
 
511
- index = data.readCellValue(index, COLUMN_PARENT);
575
+ index = uint32[index * ELEMENT_WORD_COUNT + COLUMN_PARENT];
512
576
  }
513
577
  }
514
578
 
@@ -520,27 +584,25 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
520
584
  bubble_up_update(parent) {
521
585
  let index = parent;
522
586
 
523
- const data = this.__data;
587
+ const uint32 = this.__data_uint32;
524
588
 
525
589
  while (index !== NULL_NODE) {
526
590
  index = this.balance(index);
527
591
 
528
- const child1 = data.readCellValue(index, COLUMN_CHILD_1);
529
- const child2 = data.readCellValue(index, COLUMN_CHILD_2);
592
+ const child1 = uint32[index * ELEMENT_WORD_COUNT + COLUMN_CHILD_1];
593
+ const child2 = uint32[index * ELEMENT_WORD_COUNT + COLUMN_CHILD_2];
530
594
 
531
595
  assert.notEqual(child1, NULL_NODE, 'child1 is null');
532
596
  assert.notEqual(child2, NULL_NODE, 'child2 is null');
533
597
 
534
-
535
- data.writeCellValue(index, COLUMN_HEIGHT,
536
- 1 + max2(
537
- data.readCellValue(child1, COLUMN_HEIGHT),
538
- data.readCellValue(child2, COLUMN_HEIGHT),
539
- )
598
+ uint32[index * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = 1 + max2(
599
+ uint32[child1 * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
600
+ uint32[child2 * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
540
601
  );
602
+
541
603
  this.node_set_combined_aabb(index, child1, child2);
542
604
 
543
- index = data.readCellValue(index, COLUMN_PARENT);
605
+ index = uint32[index * ELEMENT_WORD_COUNT + COLUMN_PARENT];
544
606
  }
545
607
  }
546
608
 
@@ -557,30 +619,30 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
557
619
  return;
558
620
  }
559
621
 
560
- const data = this.__data;
622
+ const uint32 = this.__data_uint32;
561
623
 
562
- const parent = data.readCellValue(leaf, COLUMN_PARENT);
563
- const grandParent = data.readCellValue(parent, COLUMN_PARENT);
624
+ const parent = uint32[leaf * ELEMENT_WORD_COUNT + COLUMN_PARENT];
625
+ const grandParent = uint32[parent * ELEMENT_WORD_COUNT + COLUMN_PARENT];
564
626
 
565
627
  let sibling;
566
628
 
567
- const parent_child1 = data.readCellValue(parent, COLUMN_CHILD_1);
629
+ const parent_child1 = uint32[parent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1];
568
630
 
569
631
  if (parent_child1 === leaf) {
570
- sibling = data.readCellValue(parent, COLUMN_CHILD_2);
632
+ sibling = uint32[parent * ELEMENT_WORD_COUNT + COLUMN_CHILD_2];
571
633
  } else {
572
634
  sibling = parent_child1;
573
635
  }
574
636
 
575
637
  if (grandParent !== NULL_NODE) {
576
638
  // Destroy parent and connect sibling to grandParent.
577
- const grand_parent_child1 = data.readCellValue(grandParent, COLUMN_CHILD_1);
639
+ const grand_parent_child1 = uint32[grandParent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1];
578
640
  if (grand_parent_child1 === parent) {
579
- data.writeCellValue(grandParent, COLUMN_CHILD_1, sibling);
641
+ uint32[grandParent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] = sibling;
580
642
  } else {
581
- data.writeCellValue(grandParent, COLUMN_CHILD_2, sibling);
643
+ uint32[grandParent * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = sibling;
582
644
  }
583
- data.writeCellValue(sibling, COLUMN_PARENT, grandParent);
645
+ uint32[sibling * ELEMENT_WORD_COUNT + COLUMN_PARENT] = grandParent;
584
646
 
585
647
  this.release_node(parent);
586
648
 
@@ -589,7 +651,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
589
651
 
590
652
  } else {
591
653
  this.__root = sibling;
592
- data.writeCellValue(sibling, COLUMN_PARENT, NULL_NODE);
654
+ uint32[sibling * ELEMENT_WORD_COUNT + COLUMN_PARENT] = NULL_NODE;
593
655
  this.release_node(parent);
594
656
  }
595
657
  }
@@ -605,15 +667,14 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
605
667
  assert.notEqual(iA, NULL_NODE, 'input is a null node');
606
668
 
607
669
  //b2TreeNode* A = m_nodes + iA;
670
+ const uint32 = this.__data_uint32;
608
671
 
609
- const data = this.__data;
610
-
611
- if (this.node_is_leaf(iA) || data.readCellValue(iA, COLUMN_HEIGHT) < 2) {
672
+ if (this.node_is_leaf(iA) || uint32[iA * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] < 2) {
612
673
  return iA;
613
674
  }
614
675
 
615
- const iB = data.readCellValue(iA, COLUMN_CHILD_1);
616
- const iC = data.readCellValue(iA, COLUMN_CHILD_2);
676
+ const iB = uint32[iA * ELEMENT_WORD_COUNT + COLUMN_CHILD_1];
677
+ const iC = uint32[iA * ELEMENT_WORD_COUNT + COLUMN_CHILD_2];
617
678
 
618
679
  assert.greaterThanOrEqual(iB, 0);
619
680
  assert.lessThan(iB, this.node_capacity);
@@ -623,12 +684,12 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
623
684
  //b2TreeNode* B = m_nodes + iB;
624
685
  //b2TreeNode* C = m_nodes + iC;
625
686
 
626
- const balance = data.readCellValue(iC, COLUMN_HEIGHT) - data.readCellValue(iB, COLUMN_HEIGHT);
687
+ const balance = uint32[iC * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] - uint32[iB * ELEMENT_WORD_COUNT + COLUMN_HEIGHT];
627
688
 
628
689
  // Rotate C up
629
690
  if (balance > 1) {
630
- const iF = data.readCellValue(iC, COLUMN_CHILD_1);
631
- const iG = data.readCellValue(iC, COLUMN_CHILD_2);
691
+ const iF = uint32[iC * ELEMENT_WORD_COUNT + COLUMN_CHILD_1];
692
+ const iG = uint32[iC * ELEMENT_WORD_COUNT + COLUMN_CHILD_2];
632
693
 
633
694
  // b2TreeNode* F = m_nodes + iF;
634
695
  // b2TreeNode* G = m_nodes + iG;
@@ -639,69 +700,63 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
639
700
  assert.lessThan(iG, this.node_capacity);
640
701
 
641
702
  // Swap A and C
642
- data.writeCellValue(iC, COLUMN_CHILD_1, iA);
703
+ uint32[iC * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] = iA;
643
704
 
644
- const a_parent = data.readCellValue(iA, COLUMN_PARENT);
705
+ const a_parent = uint32[iA * ELEMENT_WORD_COUNT + COLUMN_PARENT];
645
706
 
646
- data.writeCellValue(iC, COLUMN_PARENT, a_parent);
647
- data.writeCellValue(iA, COLUMN_PARENT, iC);
707
+ uint32[iC * ELEMENT_WORD_COUNT + COLUMN_PARENT] = a_parent;
708
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_PARENT] = iC;
648
709
 
649
710
  // A's old parent should point to C
650
711
  if (a_parent !== NULL_NODE) {
651
- if (data.readCellValue(a_parent, COLUMN_CHILD_1) === iA) {
652
- data.writeCellValue(a_parent, COLUMN_CHILD_1, iC);
712
+ if (uint32[a_parent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] === iA) {
713
+ uint32[a_parent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] = iC;
653
714
  } else {
654
715
  //b2Assert(m_nodes[C->parent].child2 == iA);
655
- data.writeCellValue(a_parent, COLUMN_CHILD_2, iC);
716
+ uint32[a_parent * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = iC;
656
717
  }
657
718
  } else {
658
719
  this.__root = iC;
659
720
  }
660
721
 
661
722
  // Rotate
662
- if (data.readCellValue(iF, COLUMN_HEIGHT) > data.readCellValue(iG, COLUMN_HEIGHT)) {
723
+ if (uint32[iF * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] > uint32[iG * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]) {
663
724
 
664
- data.writeCellValue(iC, COLUMN_CHILD_2, iF);
665
- data.writeCellValue(iA, COLUMN_CHILD_2, iG);
666
- data.writeCellValue(iG, COLUMN_PARENT, iA);
725
+ uint32[iC * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = iF;
726
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = iG;
727
+
728
+ uint32[iG * ELEMENT_WORD_COUNT + COLUMN_PARENT] = iA;
667
729
 
668
730
  this.node_set_combined_aabb(iA, iB, iG);
669
731
  this.node_set_combined_aabb(iC, iA, iF);
670
732
 
671
- data.writeCellValue(iA, COLUMN_HEIGHT,
672
- 1 + max2(
673
- data.readCellValue(iB, COLUMN_HEIGHT),
674
- data.readCellValue(iG, COLUMN_HEIGHT)
675
- )
733
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = 1 + max2(
734
+ uint32[iB * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
735
+ uint32[iG * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]
676
736
  );
677
737
 
678
- data.writeCellValue(iC, COLUMN_HEIGHT,
679
- 1 + max2(
680
- data.readCellValue(iA, COLUMN_HEIGHT),
681
- data.readCellValue(iF, COLUMN_HEIGHT)
682
- )
738
+ uint32[iC * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = 1 + max2(
739
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
740
+ uint32[iF * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]
683
741
  );
742
+
684
743
  } else {
685
- data.writeCellValue(iC, COLUMN_CHILD_2, iG);
686
- data.writeCellValue(iA, COLUMN_CHILD_2, iF);
744
+ uint32[iC * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = iG;
745
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = iF;
687
746
 
688
- data.writeCellValue(iF, COLUMN_PARENT, iA);
747
+ uint32[iF * ELEMENT_WORD_COUNT + COLUMN_PARENT] = iA;
689
748
 
690
749
  this.node_set_combined_aabb(iA, iB, iF);
691
750
  this.node_set_combined_aabb(iC, iA, iG);
692
751
 
693
- data.writeCellValue(iA, COLUMN_HEIGHT,
694
- 1 + max2(
695
- data.readCellValue(iB, COLUMN_HEIGHT),
696
- data.readCellValue(iF, COLUMN_HEIGHT)
697
- )
752
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = 1 + max2(
753
+ uint32[iB * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
754
+ uint32[iF * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]
698
755
  );
699
756
 
700
- data.writeCellValue(iC, COLUMN_HEIGHT,
701
- 1 + max2(
702
- data.readCellValue(iA, COLUMN_HEIGHT),
703
- data.readCellValue(iG, COLUMN_HEIGHT)
704
- )
757
+ uint32[iC * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = 1 + max2(
758
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
759
+ uint32[iG * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]
705
760
  );
706
761
 
707
762
  }
@@ -711,8 +766,8 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
711
766
 
712
767
  // Rotate B up
713
768
  if (balance < -1) {
714
- const iD = data.readCellValue(iB, COLUMN_CHILD_1);
715
- const iE = data.readCellValue(iB, COLUMN_CHILD_2);
769
+ const iD = uint32[iB * ELEMENT_WORD_COUNT + COLUMN_CHILD_1];
770
+ const iE = uint32[iB * ELEMENT_WORD_COUNT + COLUMN_CHILD_2];
716
771
 
717
772
  assert.greaterThanOrEqual(iD, 0);
718
773
  assert.lessThan(iD, this.node_capacity);
@@ -720,68 +775,64 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
720
775
  assert.lessThan(iE, this.node_capacity);
721
776
 
722
777
  // Swap A and B
723
- data.writeCellValue(iB, COLUMN_CHILD_1, iA);
724
- const a_parent = data.readCellValue(iA, COLUMN_PARENT);
725
- data.writeCellValue(iB, COLUMN_PARENT, a_parent);
726
- data.writeCellValue(iA, COLUMN_PARENT, iB);
778
+ uint32[iB * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] = iA;
779
+ const a_parent = uint32[iA * ELEMENT_WORD_COUNT + COLUMN_PARENT];
780
+ uint32[iB * ELEMENT_WORD_COUNT + COLUMN_PARENT] = a_parent;
781
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_PARENT] = iB;
727
782
 
728
783
  // A's old parent should point to B
729
784
  if (a_parent !== NULL_NODE) {
730
- if (data.readCellValue(a_parent, COLUMN_CHILD_1) === iA) {
731
- data.writeCellValue(a_parent, COLUMN_CHILD_1, iB)
785
+ if (uint32[a_parent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] === iA) {
786
+ uint32[a_parent * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] = iB;
732
787
  } else {
733
788
  //b2Assert(m_nodes[B->parent].child2 == iA);
734
- data.writeCellValue(a_parent, COLUMN_CHILD_2, iB);
789
+ assert.equal(uint32[uint32[iB * ELEMENT_WORD_COUNT + COLUMN_PARENT] * ELEMENT_WORD_COUNT + COLUMN_CHILD_2], iA);
790
+
791
+ uint32[a_parent * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = iB;
735
792
  }
736
793
  } else {
737
794
  this.__root = iB;
738
795
  }
739
796
 
740
797
  // Rotate
741
- if (data.readCellValue(iD, COLUMN_HEIGHT) > data.readCellValue(iE, COLUMN_HEIGHT)) {
798
+ if (uint32[iD * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] > uint32[iE * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]) {
742
799
 
743
- data.writeCellValue(iB, COLUMN_CHILD_2, iD);
744
- data.writeCellValue(iA, COLUMN_CHILD_1, iE);
745
- data.writeCellValue(iE, COLUMN_PARENT, iA);
800
+ uint32[iB * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = iD;
801
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] = iE;
802
+ uint32[iE * ELEMENT_WORD_COUNT + COLUMN_PARENT] = iA;
746
803
 
747
804
  this.node_set_combined_aabb(iA, iC, iE);
748
805
  this.node_set_combined_aabb(iB, iA, iD);
749
806
 
750
- data.writeCellValue(iA, COLUMN_HEIGHT,
751
- 1 + max2(
752
- data.readCellValue(iC, COLUMN_HEIGHT),
753
- data.readCellValue(iE, COLUMN_HEIGHT)
754
- )
807
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = 1 + max2(
808
+ uint32[iC * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
809
+ uint32[iE * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]
755
810
  );
756
811
 
757
- data.writeCellValue(iB, COLUMN_HEIGHT,
758
- 1 + max2(
759
- data.readCellValue(iA, COLUMN_HEIGHT),
760
- data.readCellValue(iD, COLUMN_HEIGHT)
761
- )
812
+ uint32[iB * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = 1 + max2(
813
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
814
+ uint32[iD * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]
762
815
  );
763
816
 
764
817
  } else {
765
- data.writeCellValue(iB, COLUMN_CHILD_2, iE);
766
- data.writeCellValue(iA, COLUMN_CHILD_1, iD);
767
- data.writeCellValue(iD, COLUMN_PARENT, iA);
818
+
819
+ uint32[iB * ELEMENT_WORD_COUNT + COLUMN_CHILD_2] = iE;
820
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_CHILD_1] = iD;
821
+ uint32[iD * ELEMENT_WORD_COUNT + COLUMN_PARENT] = iA;
768
822
 
769
823
  this.node_set_combined_aabb(iA, iC, iD);
770
824
  this.node_set_combined_aabb(iB, iA, iE);
771
825
 
772
- data.writeCellValue(iA, COLUMN_HEIGHT,
773
- 1 + max2(
774
- data.readCellValue(iC, COLUMN_HEIGHT),
775
- data.readCellValue(iD, COLUMN_HEIGHT)
776
- )
826
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = 1 + max2(
827
+ uint32[iC * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
828
+ uint32[iD * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]
777
829
  );
778
830
 
779
- data.writeCellValue(iB, COLUMN_HEIGHT,
780
- 1 + max2(
781
- data.readCellValue(iA, COLUMN_HEIGHT),
782
- data.readCellValue(iE, COLUMN_HEIGHT)
783
- )
831
+ uint32[iB * ELEMENT_WORD_COUNT + COLUMN_HEIGHT] = 1 + max2(
832
+ uint32[iA * ELEMENT_WORD_COUNT + COLUMN_HEIGHT],
833
+ uint32[iE * ELEMENT_WORD_COUNT + COLUMN_HEIGHT]
784
834
  );
835
+
785
836
  }
786
837
 
787
838
  return iB;
@@ -806,7 +857,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
806
857
  stack[cursor++] = root;
807
858
  }
808
859
 
809
- const data = this.__data;
860
+ const uint32 = this.__data_uint32;
810
861
 
811
862
  while (cursor > 0) {
812
863
  cursor--;
@@ -815,15 +866,14 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
815
866
 
816
867
  callback.call(ctx, node, this);
817
868
 
818
- const child1 = data.readCellValue(node, COLUMN_CHILD_1);
819
- const child2 = data.readCellValue(node, COLUMN_CHILD_2);
869
+ const node_address = node * ELEMENT_WORD_COUNT;
820
870
 
821
- if (child1 !== NULL_NODE) {
822
- stack[cursor++] = child1;
823
- }
871
+ const child1 = uint32[node_address + COLUMN_CHILD_1];
872
+ const child2 = uint32[node_address + COLUMN_CHILD_2];
824
873
 
825
- if (child2 !== NULL_NODE) {
874
+ if (child1 !== NULL_NODE) {
826
875
  stack[cursor++] = child2;
876
+ stack[cursor++] = child1;
827
877
  }
828
878
 
829
879
  }