@woosh/meep-engine 2.74.0 → 2.75.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/meep.cjs +202 -204
  3. package/build/meep.min.js +1 -1
  4. package/build/meep.module.js +202 -204
  5. package/package.json +1 -1
  6. package/src/core/binary/UINT32_MAX.js +5 -0
  7. package/src/core/bvh2/bvh3/BVH.js +44 -2
  8. package/src/core/bvh2/bvh3/BVH.spec.js +45 -0
  9. package/src/core/bvh2/bvh3/build_triangle_morton_codes.js +73 -0
  10. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_morton.js +5 -101
  11. package/src/core/bvh2/bvh3/ebvh_build_hierarchy.js +59 -0
  12. package/src/core/bvh2/bvh3/query/bvh_query_user_data_nearest_to_point.js +31 -32
  13. package/src/core/bvh2/bvh3/query/bvh_query_user_data_nearest_to_point.spec.js +139 -0
  14. package/src/core/collection/SCRATCH_UINT32_TRAVERSAL_STACK.js +1 -0
  15. package/src/core/events/signal/SignalBinding.js +18 -16
  16. package/src/core/geom/3d/aabb/aabb3_signed_distance_sqr_to_point.js +1 -0
  17. package/src/core/geom/3d/aabb/aabb3_unsigned_distance_sqr_to_point.js +36 -0
  18. package/src/core/model/ObservedBoolean.js +1 -1
  19. package/src/core/process/worker/OnDemandWorkerManager.js +5 -1
  20. package/src/engine/asset/loaders/ArrayBufferLoader.js +13 -15
  21. package/src/engine/asset/loaders/image/ImageDecoderWorker.js +1 -1
  22. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +5 -7
  23. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +1 -1
  24. package/src/engine/asset/loaders/image/png/PNG.js +339 -332
  25. package/src/engine/asset/loaders/image/png/PNGReader.js +59 -16
  26. package/src/engine/asset/loaders/image/png/prototypePNG.js +13 -4
  27. package/src/engine/graphics/texture/virtual/v2/{SparseTexture.js → PageTexture.js} +62 -18
  28. package/src/engine/graphics/texture/virtual/v2/ResidentTileTexture.js +46 -0
  29. package/src/engine/graphics/texture/virtual/v2/{TileLoader.js → VirtualTextureTileLoader.js} +11 -8
  30. package/src/engine/graphics/texture/virtual/v2/{UsageMetadata.js → VirtualTextureUsage.js} +2 -8
  31. package/src/engine/graphics/texture/virtual/v2/{VirtualTextureManager.js → VirtualTextureUsageUpdater.js} +7 -5
  32. package/src/engine/graphics/texture/virtual/v2/debug/ResidencyDebugView.js +17 -5
  33. package/src/engine/graphics/texture/virtual/v2/debug/UsageDebugView.js +1 -1
  34. package/src/engine/graphics/texture/virtual/v2/debug/UsagePyramidDebugView.js +1 -1
  35. package/src/engine/graphics/texture/virtual/v2/prototype.js +78 -59
  36. package/src/engine/graphics/texture/virtual/v2/tile/{TextureTile.js → VirtualTextureTile.js} +2 -2
  37. package/src/engine/graphics/texture/virtual/v2/tile/compose_tile_address.js +4 -0
  38. /package/src/engine/graphics/texture/virtual/v2/{ShaderUsage.js → VirtualTextureUsageShader.js} +0 -0
@@ -1,3 +1,6 @@
1
+ import { aabb3_unsigned_distance_sqr_to_point } from "../../../geom/3d/aabb/aabb3_unsigned_distance_sqr_to_point.js";
2
+ import { randomFloatBetween } from "../../../math/random/randomFloatBetween.js";
3
+ import { seededRandom } from "../../../math/random/seededRandom.js";
1
4
  import { BVH } from "../BVH.js";
2
5
  import { bvh_query_user_data_nearest_to_point } from "./bvh_query_user_data_nearest_to_point.js";
3
6
 
@@ -68,3 +71,139 @@ test('two point, distance sufficient to both', () => {
68
71
 
69
72
  expect(result).toBe(0);
70
73
  });
74
+
75
+
76
+ test.skip("performance, 1M random boxes, 10k queries", () => {
77
+
78
+ const random = seededRandom(1);
79
+
80
+ const bvh = new BVH();
81
+
82
+ const min_bound = -1000;
83
+ const max_bound = 1000;
84
+
85
+ const OBJECT_COUNT = 1000000;
86
+
87
+ for (let i = 0; i < OBJECT_COUNT; i++) {
88
+ const node = bvh.allocate_node();
89
+
90
+ bvh.node_set_user_data(node, i);
91
+
92
+ const x = randomFloatBetween(random, min_bound, max_bound);
93
+ const y = randomFloatBetween(random, min_bound, max_bound);
94
+ const z = randomFloatBetween(random, min_bound, max_bound);
95
+
96
+ const extents = randomFloatBetween(random, 1, 50);
97
+
98
+ const x0 = x - extents;
99
+ const y0 = y - extents;
100
+ const z0 = z - extents;
101
+
102
+ const x1 = x + extents;
103
+ const y1 = y + extents;
104
+ const z1 = z + extents;
105
+
106
+ bvh.node_set_aabb_primitive(
107
+ node,
108
+ x0, y0, z0,
109
+ x1, y1, z1
110
+ );
111
+
112
+ bvh.insert_leaf(node);
113
+ }
114
+
115
+ const SAMPLE_POINT_COUNT = 10000;
116
+
117
+ const t0 = performance.now();
118
+
119
+ for (let i = 0; i < SAMPLE_POINT_COUNT; i++) {
120
+
121
+ const x = randomFloatBetween(random, min_bound, max_bound);
122
+ const y = randomFloatBetween(random, min_bound, max_bound);
123
+ const z = randomFloatBetween(random, min_bound, max_bound);
124
+
125
+ bvh_query_user_data_nearest_to_point(
126
+ bvh, x, y, z
127
+ );
128
+ }
129
+
130
+ const t1 = performance.now();
131
+
132
+ const duration = (t1 - t0);
133
+
134
+ console.log(`${duration / SAMPLE_POINT_COUNT}ms/query`);
135
+ });
136
+
137
+ test.skip('naive search, 1m random boxes, 10k queries', () => {
138
+
139
+ const random = seededRandom(1);
140
+
141
+ const OBJECT_COUNT = 1000000;
142
+
143
+ const boxes = new Float32Array(OBJECT_COUNT * 6);
144
+
145
+ const min_bound = -1000;
146
+ const max_bound = 1000;
147
+
148
+ const extents = 25;
149
+
150
+ for (let i = 0; i < OBJECT_COUNT; i++) {
151
+ const address = i * 6;
152
+
153
+ const x = randomFloatBetween(random, min_bound, max_bound);
154
+ const y = randomFloatBetween(random, min_bound, max_bound);
155
+ const z = randomFloatBetween(random, min_bound, max_bound);
156
+
157
+ boxes[address] = x - extents;
158
+ boxes[address + 1] = y - extents;
159
+ boxes[address + 2] = z - extents;
160
+
161
+ boxes[address + 3] = x + extents;
162
+ boxes[address + 4] = y + extents;
163
+ boxes[address + 5] = z + extents;
164
+
165
+ }
166
+
167
+ function naive_query(boxes, count, x, y, z) {
168
+ let best_distance_sqr = Infinity;
169
+ let best_index = 0;
170
+
171
+ const limit = count * 6;
172
+
173
+ for (let i = 0; i < limit; i += 6) {
174
+ const distance_sqr = aabb3_unsigned_distance_sqr_to_point(
175
+ boxes[i], boxes[i + 1], boxes[i + 2],
176
+ boxes[i + 3], boxes[i + 4], boxes[i + 5],
177
+
178
+ x, y, z
179
+ )
180
+
181
+ if (distance_sqr < best_distance_sqr) {
182
+ best_index = i;
183
+ best_distance_sqr = distance_sqr;
184
+ }
185
+ }
186
+
187
+ return best_index;
188
+ }
189
+
190
+ const SAMPLE_POINT_COUNT = 10000;
191
+
192
+ const t0 = performance.now();
193
+
194
+ for (let i = 0; i < SAMPLE_POINT_COUNT; i++) {
195
+
196
+ const x = randomFloatBetween(random, min_bound, max_bound);
197
+ const y = randomFloatBetween(random, min_bound, max_bound);
198
+ const z = randomFloatBetween(random, min_bound, max_bound);
199
+
200
+ naive_query(boxes, OBJECT_COUNT, x, y, z);
201
+ }
202
+
203
+ const t1 = performance.now();
204
+
205
+ const duration = (t1 - t0);
206
+
207
+ console.log(`${duration / SAMPLE_POINT_COUNT}ms/query`);
208
+
209
+ });
@@ -8,6 +8,7 @@ export const SCRATCH_UINT32_TRAVERSAL_STACK = new Uint32Array(781250);
8
8
 
9
9
  /**
10
10
  * Pointer used to track current top of the stack, make sure to unwind once your traversal is done
11
+ * Must be a positive integer
11
12
  * @type {number}
12
13
  */
13
14
  SCRATCH_UINT32_TRAVERSAL_STACK.pointer = 0;
@@ -1,28 +1,35 @@
1
1
  /**
2
- * @author Alex Goldring
3
- * @copyright Alex Goldring 2018
2
+ * Utility class for managing connection between listeners to signals
4
3
  */
4
+ export class SignalBinding {
5
+ /**
6
+ * State flag
7
+ * @type {boolean}
8
+ */
9
+ #linked = false;
5
10
 
11
+ get linked() {
12
+ return this.#linked;
13
+ }
6
14
 
7
- export class SignalBinding {
8
15
  /**
9
16
  *
10
17
  * @param {Signal} signal
11
18
  * @param {function} handler
12
- * @param {*} [context]
19
+ * @param {*} [context] will be passed as thisArg to the handler
13
20
  * @constructor
14
21
  */
15
22
  constructor(signal, handler, context) {
16
23
  if (typeof handler !== "function") {
17
- throw new TypeError(`handler must be a function, instead was ${handler}`);
24
+ throw new TypeError(`handler must be a function, instead was '${typeof handler}'`);
18
25
  }
19
26
 
20
27
  if (typeof signal !== "object") {
21
- throw new TypeError(`signal must be of an object, instead was ${signal}`)
28
+ throw new TypeError(`signal must be of an object, instead was '${typeof signal}'`)
22
29
  }
23
30
 
24
31
  if (typeof signal.add !== "function") {
25
- throw new TypeError(`signal.add must be a function, instead was ${signal.add}`);
32
+ throw new TypeError(`signal.add must be a function, instead was '${typeof signal.add}'`);
26
33
  }
27
34
 
28
35
  /**
@@ -43,11 +50,6 @@ export class SignalBinding {
43
50
  */
44
51
  this.context = context;
45
52
 
46
- /**
47
- * State flag
48
- * @type {boolean}
49
- */
50
- this.linked = false;
51
53
  }
52
54
 
53
55
  /**
@@ -55,11 +57,11 @@ export class SignalBinding {
55
57
  * Idempotent
56
58
  */
57
59
  link() {
58
- if (this.linked) {
60
+ if (this.#linked) {
59
61
  return;
60
62
  }
61
63
 
62
- this.linked = true;
64
+ this.#linked = true;
63
65
  this.signal.add(this.handler, this.context);
64
66
  }
65
67
 
@@ -68,11 +70,11 @@ export class SignalBinding {
68
70
  * Idempotent
69
71
  */
70
72
  unlink() {
71
- if (!this.linked) {
73
+ if (!this.#linked) {
72
74
  return;
73
75
  }
74
76
 
75
- this.linked = false;
77
+ this.#linked = false;
76
78
  this.signal.remove(this.handler, this.context);
77
79
  }
78
80
  }
@@ -45,3 +45,4 @@ export function aabb3_signed_distance_sqr_to_point(
45
45
  return -(dx * dx + dy * dy + dz * dz);
46
46
  }
47
47
  }
48
+
@@ -0,0 +1,36 @@
1
+ import { max3 } from "../../../math/max3.js";
2
+
3
+ /**
4
+ * Compute squared distance to point, value is negative if the point is inside the box
5
+ * @param {number} x0
6
+ * @param {number} y0
7
+ * @param {number} z0
8
+ * @param {number} x1
9
+ * @param {number} y1
10
+ * @param {number} z1
11
+ * @param {number} point_x
12
+ * @param {number} point_y
13
+ * @param {number} point_z
14
+ * @returns {number}
15
+ */
16
+ export function aabb3_unsigned_distance_sqr_to_point(
17
+ x0, y0, z0,
18
+ x1, y1, z1,
19
+ point_x, point_y, point_z
20
+ ) {
21
+ //do projection
22
+ const xp0 = x0 - point_x;
23
+ const xp1 = point_x - x1;
24
+ const yp0 = y0 - point_y;
25
+ const yp1 = point_y - y1;
26
+ const zp0 = z0 - point_z;
27
+ const zp1 = point_z - z1;
28
+
29
+ //calculate separation in each axis
30
+ const dx = max3(0, xp0, xp1);
31
+ const dy = max3(0, yp0, yp1);
32
+ const dz = max3(0, zp0, zp1);
33
+
34
+ //straight-line distance
35
+ return dx * dx + dy * dy + dz * dz;
36
+ }
@@ -91,7 +91,7 @@ class ObservedBoolean extends Boolean {
91
91
 
92
92
  /**
93
93
  *
94
- * @param {function} f
94
+ * @param {function(boolean)} f
95
95
  */
96
96
  process(f) {
97
97
  f(this.__value);
@@ -1,4 +1,4 @@
1
- import {assert} from "../../assert.js";
1
+ import { assert } from "../../assert.js";
2
2
 
3
3
  export class OnDemandWorkerManager {
4
4
 
@@ -35,6 +35,10 @@ export class OnDemandWorkerManager {
35
35
  this.worker = worker;
36
36
  }
37
37
 
38
+ /**
39
+ * In milliseconds
40
+ * @param {number} v
41
+ */
38
42
  setTimeout(v) {
39
43
  assert.isNonNegativeInteger(v, 'v');
40
44
 
@@ -1,8 +1,8 @@
1
+ import { noop } from "../../../core/function/Functions.js";
1
2
  import { Asset } from "../Asset.js";
2
- import { AssetLoader } from "./AssetLoader.js";
3
- import { CrossOriginKind } from "../CORS/CrossOriginKind.js";
4
3
  import { CrossOriginConfig } from "../CORS/CrossOriginConfig.js";
5
- import { noop } from "../../../core/function/Functions.js";
4
+ import { CrossOriginKind } from "../CORS/CrossOriginKind.js";
5
+ import { AssetLoader } from "./AssetLoader.js";
6
6
 
7
7
  export class ArrayBufferLoader extends AssetLoader {
8
8
  /**
@@ -90,33 +90,31 @@ export class ArrayBufferLoader extends AssetLoader {
90
90
  const reader = response.body.getReader();
91
91
  const contentLength = response.headers.get('Content-Length');
92
92
  const total = contentLength ? parseInt(contentLength) : 0;
93
- const lengthComputable = total !== 0;
94
93
  let loaded = 0;
95
94
 
96
95
  // periodically read data into the new stream tracking while download progress
97
96
  const stream = new ReadableStream({
97
+ type: "bytes",
98
98
  start(controller) {
99
99
 
100
- readData();
100
+ pump();
101
101
 
102
- function readData() {
102
+ function pump() {
103
103
 
104
104
  reader.read().then(({ done, value }) => {
105
105
 
106
106
  if (done) {
107
-
107
+ // no more data, we're done
108
108
  controller.close();
109
+ return;
110
+ }
109
111
 
110
- } else {
111
-
112
- loaded += value.byteLength;
113
-
114
- progress(loaded, length);
112
+ loaded += value.byteLength;
115
113
 
116
- controller.enqueue(value);
117
- readData();
114
+ progress(loaded, total);
118
115
 
119
- }
116
+ controller.enqueue(value);
117
+ pump();
120
118
 
121
119
  });
122
120
 
@@ -23,7 +23,7 @@ async function decode_png(png_bytes) {
23
23
  width,
24
24
  height,
25
25
  itemSize: uint_channels.itemSize,
26
- bitDepth: png.bitDepth
26
+ bitDepth: 8
27
27
  });
28
28
  });
29
29
  }
@@ -1,12 +1,11 @@
1
- import { AssetLoader } from "../AssetLoader.js";
2
- import { GameAssetType } from "../../GameAssetType.js";
1
+ import { computeFileExtension } from "../../../../core/path/computeFileExtension.js";
3
2
  import { convertTexture2Sampler2D } from "../../../graphics/texture/sampler/convertTexture2Sampler2D.js";
4
- import { ImageRGBADataAsset } from "./ImageRGBADataAsset.js";
3
+ import { GameAssetType } from "../../GameAssetType.js";
5
4
  import { ArrayBufferLoader } from "../ArrayBufferLoader.js";
5
+ import { AssetLoader } from "../AssetLoader.js";
6
6
  import { CodecWithFallback } from "./codec/CodecWithFallback.js";
7
7
  import { ThreadedImageDecoder } from "./codec/ThreadedImageDecoder.js";
8
- import { NativeImageDecoder } from "./codec/NativeImageDecoder.js";
9
- import { computeFileExtension } from "../../../../core/path/computeFileExtension.js";
8
+ import { ImageRGBADataAsset } from "./ImageRGBADataAsset.js";
10
9
 
11
10
  const ASSET_TYPE_ARRAY_BUFFER = "arraybuffer";
12
11
 
@@ -16,7 +15,7 @@ export class ImageRGBADataLoader extends AssetLoader {
16
15
 
17
16
  this.decoder = new CodecWithFallback(
18
17
  new ThreadedImageDecoder(),
19
- new NativeImageDecoder()
18
+ // new NativeImageDecoder()
20
19
  );
21
20
  }
22
21
 
@@ -58,7 +57,6 @@ export class ImageRGBADataLoader extends AssetLoader {
58
57
 
59
58
  const bitmap = await this.__decode_via_worker(path, scope);
60
59
 
61
-
62
60
  let data;
63
61
 
64
62
  const bitDepth = bitmap.bitDepth;
@@ -21,7 +21,7 @@ export class ThreadedImageDecoder extends Codec {
21
21
  */
22
22
  this.worker = new OnDemandWorkerManager(workerBuilder.build());
23
23
 
24
- this.worker.setTimeout(200);
24
+ this.worker.setTimeout(1200);
25
25
  }
26
26
 
27
27
  async test(data) {