@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
@@ -140,6 +140,8 @@ PNGReader.prototype.decodeChunk = function () {
140
140
 
141
141
  }
142
142
 
143
+ // console.log(`chunk: ${type}`);
144
+
143
145
 
144
146
  switch (type) {
145
147
  case 'IHDR':
@@ -157,8 +159,11 @@ PNGReader.prototype.decodeChunk = function () {
157
159
  case 'IEND':
158
160
  this.decodeIEND(chunk);
159
161
  break;
162
+ case 'sRGB':
163
+ this.decodesRGB(chunk);
164
+ break;
160
165
  default:
161
- //console.log(`Unsupported block ${type}`);
166
+ console.warn(`Unsupported block ${type}`);
162
167
  break;
163
168
  }
164
169
 
@@ -166,6 +171,19 @@ PNGReader.prototype.decodeChunk = function () {
166
171
 
167
172
  };
168
173
 
174
+
175
+ /**
176
+ * https://www.w3.org/TR/2003/REC-PNG-20031110/#11sRGB
177
+ * @param {Uint8Array} chunk
178
+ */
179
+ PNGReader.prototype.decodesRGB = function (chunk) {
180
+
181
+ const rendering_intent = readUInt8(chunk, 0);
182
+
183
+ // TODO add metadata to the PNG representation
184
+ }
185
+
186
+
169
187
  /**
170
188
  * https://www.w3.org/TR/PNG/#11tEXt
171
189
  * @param {Uint8Array} chunk
@@ -294,17 +312,19 @@ PNGReader.prototype.interlaceNone = function (data) {
294
312
 
295
313
  const png = this.png;
296
314
 
297
- const bits_per_pixel = png.bitDepth;
298
- const bits_per_line = png.colors * bits_per_pixel;
299
- const bytes_per_pixel = Math.max(1, bits_per_line / 8);
315
+ const depth = png.bitDepth;
316
+ const bits_per_line = png.colors * depth;
317
+ const bytes_per_pixel = bits_per_line / 8;
300
318
 
301
319
  const width = png.width;
302
320
  const height = png.height;
303
321
 
304
322
  // color bytes per row
305
- const color_bytes_per_row = bytes_per_pixel * width;
323
+ const color_bytes_per_row = Math.ceil(bytes_per_pixel * width);
306
324
 
307
- const pixels = new Uint8Array(bytes_per_pixel * width * height);
325
+ const output_bytes_per_row = Math.ceil(bytes_per_pixel) * width;
326
+
327
+ const pixels = new Uint8Array(output_bytes_per_row * height);
308
328
 
309
329
  let offset = 0;
310
330
 
@@ -320,7 +340,38 @@ PNGReader.prototype.interlaceNone = function (data) {
320
340
 
321
341
  switch (header) {
322
342
  case 0:
323
- this.unFilterNone(data, scanline_address, pixels, bytes_per_pixel, offset, color_bytes_per_row);
343
+ // NONE
344
+ if (depth === 1) {
345
+ for (let x = 0; x < output_bytes_per_row; x++) {
346
+ const q = x >>> 4;
347
+ const datum = data[q + scanline_address];
348
+ const shift = ((x) & 0x7);
349
+ const out_value = (datum >>> shift) & 0x1;
350
+ pixels[offset + x] = out_value;
351
+ }
352
+ } else if (depth === 2) {
353
+ for (let x = 0; x < output_bytes_per_row; x++) {
354
+ const q = x >>> 2;
355
+ const datum = data[q + scanline_address];
356
+ const shift = ((~x) & 0x3) << 1;
357
+ const out_value = (datum >>> shift) & 0x3;
358
+ pixels[offset + x] = out_value;
359
+ }
360
+ } else if (depth === 4) {
361
+ for (let x = 0; x < output_bytes_per_row; x++) {
362
+ const q = x >>> 1;
363
+ const datum = data[q + scanline_address];
364
+ const shift = ((~x) & 0x1) << 2;
365
+ const out_value = (datum >>> shift) & 0xF;
366
+ pixels[offset + x] = out_value;
367
+ }
368
+ } else if (depth === 8) {
369
+ for (let x = 0; x < output_bytes_per_row; x++) {
370
+ pixels[offset + x] = data[x + scanline_address];
371
+ }
372
+ } else {
373
+ throw new Error(`unsupported bit depth ${depth}`)
374
+ }
324
375
  break;
325
376
  case 1:
326
377
  this.unFilterSub(data, scanline_address, pixels, bytes_per_pixel, offset, color_bytes_per_row);
@@ -338,7 +389,7 @@ PNGReader.prototype.interlaceNone = function (data) {
338
389
  throw new Error(`unknown filtered scanline type '${header}'`);
339
390
  }
340
391
 
341
- offset += color_bytes_per_row;
392
+ offset += output_bytes_per_row;
342
393
 
343
394
  }
344
395
 
@@ -356,14 +407,6 @@ PNGReader.prototype.interlaceAdam7 = function (data) {
356
407
 
357
408
  // Unfiltering
358
409
 
359
- /**
360
- * No filtering, direct copy
361
- */
362
- PNGReader.prototype.unFilterNone = function (scanline, scanline_offset, pixels, bpp, of, length) {
363
- for (let i = 0; i < length; i++) {
364
- pixels[of + i] = scanline[i + scanline_offset];
365
- }
366
- };
367
410
 
368
411
  /**
369
412
  * The Sub() filter transmits the difference between each byte and the value
@@ -1,13 +1,22 @@
1
+ import { Sampler2D } from "../../../../graphics/texture/sampler/Sampler2D.js";
1
2
  import sampler2D2Canvas from "../../../../graphics/texture/sampler/Sampler2D2Canvas.js";
3
+ import { AssetRequestScope } from "../../../AssetRequestScope.js";
2
4
  import { ArrayBufferLoader } from "../../ArrayBufferLoader.js";
3
5
  import { PNGReader } from "./PNGReader.js";
4
- import { Sampler2D } from "../../../../graphics/texture/sampler/Sampler2D.js";
5
6
 
6
7
  const array_loader = new ArrayBufferLoader();
7
8
 
8
9
 
10
+ // const path = 'moicon/ISO 7010 - Safety Signs (3)/ISO 7010 - Safety Signs/Emergency/400px/E001 – Emergency exit (left hand).png';
11
+ // const path = 'data/textures/utility/vt/uv_map_reference/5-2-1.png';
12
+ // const path = 'data/textures/utility/vt/uv_map_reference/6-62-60.png';
13
+ // const path = 'data/textures/utility/vt/uv_map_reference/5-11-5.png';
14
+ // const path = 'data/textures/utility/vt/uv_map_reference/1-0-0.png';
15
+ // const path = 'data/textures/utility/vt/uv_map_reference/5-3-0.png';
16
+ // const path = 'data/textures/utility/vt/uv_map_reference/5-21-14.png';
17
+ const path = 'data/textures/utility/vt/uv_map_reference/6-39-33.png';
9
18
 
10
- array_loader.load('moicon/ISO 7010 - Safety Signs (3)/ISO 7010 - Safety Signs/Emergency/400px/E001 – Emergency exit (left hand).png',(asset)=>{
19
+ array_loader.load(new AssetRequestScope(), path, (asset) => {
11
20
 
12
21
  const array = asset.create();
13
22
 
@@ -19,9 +28,9 @@ array_loader.load('moicon/ISO 7010 - Safety Signs (3)/ISO 7010 - Safety Signs/Em
19
28
 
20
29
  const uint8Data = png.getUint8Data();
21
30
 
22
- const sampler = new Sampler2D(uint8Data.data,uint8Data.itemSize,png.getWidth(), png.getHeight());
31
+ const sampler = new Sampler2D(uint8Data.data, uint8Data.itemSize, png.getWidth(), png.getHeight());
23
32
 
24
- const canvas = sampler2D2Canvas(sampler,1,0);
33
+ const canvas = sampler2D2Canvas(sampler, 1, 0);
25
34
 
26
35
  document.body.appendChild(canvas);
27
36
 
@@ -2,11 +2,12 @@ import { WebGLRenderTarget } from "three";
2
2
  import { BitSet } from "../../../../../core/binary/BitSet.js";
3
3
  import { Cache } from "../../../../../core/cache/Cache.js";
4
4
  import { array_copy } from "../../../../../core/collection/array/array_copy.js";
5
+ import { HashMap } from "../../../../../core/collection/map/HashMap.js";
5
6
  import { passThrough, strictEquals } from "../../../../../core/function/Functions.js";
6
7
  import { max2 } from "../../../../../core/math/max2.js";
7
8
  import { min2 } from "../../../../../core/math/min2.js";
8
9
  import { tile_address_to_finger_print } from "./tile/tile_address_to_finger_print.js";
9
- import { TileLoader } from "./TileLoader.js";
10
+ import { VirtualTextureTileLoader } from "./VirtualTextureTileLoader.js";
10
11
 
11
12
  /**
12
13
  * How much extra data to store in cache (in bytes)
@@ -14,12 +15,22 @@ import { TileLoader } from "./TileLoader.js";
14
15
  */
15
16
  const DEFAULT_CACHE_SIZE = 16 * 1024 * 1024;
16
17
 
17
- export class SparseTexture {
18
+ export class PageTexture {
18
19
  #page_texture = new WebGLRenderTarget(1, 1);
19
20
 
20
21
  #page_texture_size = [1, 1];
21
22
 
22
- #version = 0;
23
+ /**
24
+ * Used internally to track number of times `update` method was called
25
+ * @type {number}
26
+ */
27
+ update_count = 0;
28
+
29
+ /**
30
+ * Track updates to page content, whenever a tile is made resident or is removed - this number goes up by 1
31
+ * @type {number}
32
+ */
33
+ version = 0;
23
34
 
24
35
  /**
25
36
  * Maximum number of new page assignments per single update cycle
@@ -35,7 +46,7 @@ export class SparseTexture {
35
46
 
36
47
  /**
37
48
  *
38
- * @type {TextureTile[]}
49
+ * @type {VirtualTextureTile[]}
39
50
  */
40
51
  #resident_tiles = [];
41
52
 
@@ -43,6 +54,15 @@ export class SparseTexture {
43
54
  return this.#resident_tiles;
44
55
  }
45
56
 
57
+ /**
58
+ *
59
+ * @type {HashMap<number, VirtualTextureTile>}
60
+ */
61
+ #resident_tile_lookup = new HashMap({
62
+ keyHashFunction: passThrough,
63
+ keyEqualityFunction: strictEquals,
64
+ });
65
+
46
66
  #page_slot_occupancy = new BitSet();
47
67
 
48
68
  #tile_resolution = 128;
@@ -61,7 +81,7 @@ export class SparseTexture {
61
81
  */
62
82
  #prefetch_factor = 0.33;
63
83
 
64
- #loader = new TileLoader();
84
+ #loader = new VirtualTextureTileLoader();
65
85
 
66
86
  /**
67
87
  *
@@ -75,7 +95,7 @@ export class SparseTexture {
75
95
 
76
96
  /**
77
97
  *
78
- * @param {TextureTile} tile
98
+ * @param {VirtualTextureTile} tile
79
99
  */
80
100
  #handle_tile_loaded(tile) {
81
101
  const finderPrint = tile.finder_print;
@@ -112,7 +132,8 @@ export class SparseTexture {
112
132
 
113
133
  this.#residency_tile_capacity = x * y;
114
134
 
115
- this.#loader.queue_limit = max2(16, this.#residency_tile_capacity);
135
+ // Limit the queue to be able to load no more than an entire page, trying to load more would be wasteful as we wouldn't be able to use that data immediately anyway
136
+ this.#loader.queue_limit = max2(1, this.#residency_tile_capacity);
116
137
  }
117
138
 
118
139
 
@@ -129,7 +150,7 @@ export class SparseTexture {
129
150
  /**
130
151
  * Tiles that are not currently resident live here
131
152
  * key is the tile's "fingerprint"
132
- * @type {Cache<number,TextureTile>}
153
+ * @type {Cache<number,VirtualTextureTile>}
133
154
  */
134
155
  #tile_cache = new Cache({
135
156
  keyHashFunction: passThrough,
@@ -183,15 +204,21 @@ export class SparseTexture {
183
204
 
184
205
  removed.page_slot = -1;
185
206
 
207
+ const fingerprint = removed.finder_print;
208
+
209
+ this.#resident_tile_lookup.delete(fingerprint);
210
+
186
211
  // push into cache
187
- this.#tile_cache.put(removed.finder_print, removed);
212
+ this.#tile_cache.put(fingerprint, removed);
213
+
214
+ this.version++;
188
215
 
189
216
  return true;
190
217
  }
191
218
 
192
219
  /**
193
220
  *
194
- * @param {TextureTile} tile
221
+ * @param {VirtualTextureTile} tile
195
222
  */
196
223
  #make_resident(tile) {
197
224
 
@@ -208,9 +235,13 @@ export class SparseTexture {
208
235
  }
209
236
 
210
237
  tile.page_slot = slot;
238
+ tile.last_used_time = this.update_count;
211
239
 
212
240
  this.#page_slot_occupancy.set(slot, true);
213
241
  this.#resident_tiles.push(tile);
242
+ this.#resident_tile_lookup.set(tile.finder_print, tile);
243
+
244
+ this.version++;
214
245
 
215
246
  return true;
216
247
  }
@@ -234,7 +265,7 @@ export class SparseTexture {
234
265
 
235
266
  /**
236
267
  *
237
- * @param {UsageMetadata} usage
268
+ * @param {VirtualTextureUsage} usage
238
269
  */
239
270
  update_usage(usage) {
240
271
  const usage_occupancy = usage.occupancy;
@@ -256,17 +287,27 @@ export class SparseTexture {
256
287
 
257
288
  const fingerPrint = tile_address_to_finger_print(tile_address);
258
289
 
259
- const tile = this.#tile_cache.get(fingerPrint);
290
+ let tile = this.#resident_tile_lookup.get(fingerPrint);
291
+
292
+ if (tile !== undefined) {
293
+ // already resident
294
+
295
+ // touch to prevent eviction
296
+ tile.last_used_time = this.update_count;
297
+ remaining_slots--;
298
+ fetch_limit--;
299
+
300
+ continue;
301
+ }
302
+
303
+ tile = this.#tile_cache.get(fingerPrint);
304
+
260
305
  if (tile === null) {
261
306
  this.#loader.enqueue(fingerPrint);
262
307
  } else if (remaining_slots > 0) {
263
308
  // found in cache, and we have some slots remaining to write into
264
309
 
265
-
266
- // touch to prevent eviction
267
- tile.last_used_time = this.#version;
268
-
269
- if (tile.page_slot === -1 && writes_remaining > 0) {
310
+ if (writes_remaining > 0) {
270
311
  // tile is not active, and we can write it
271
312
  writes_remaining--;
272
313
  this.#make_resident(tile);
@@ -280,12 +321,15 @@ export class SparseTexture {
280
321
 
281
322
  this.#loader.update_usage(usage);
282
323
 
283
- this.#version++;
324
+ this.update_count++;
284
325
  }
285
326
 
286
327
  dispose() {
287
328
  this.#page_texture.dispose();
288
329
  this.#tile_cache.clear();
289
330
  this.#page_slot_occupancy.reset();
331
+
332
+ this.#resident_tiles.splice(0, this.#resident_tiles.length);
333
+ this.#resident_tile_lookup.clear();
290
334
  }
291
335
  }
@@ -0,0 +1,46 @@
1
+ import { compose_tile_address } from "./tile/compose_tile_address.js";
2
+
3
+ /**
4
+ * Represents entire mip pyramid of tiles, where each tile slot points to an actual resident tile
5
+ */
6
+ export class ResidentTileTexture {
7
+ #resolution = 0;
8
+ #pyramid = new Uint32Array(0);
9
+
10
+
11
+ /**
12
+ *
13
+ * @param {number} resolution
14
+ */
15
+ set resolution(resolution) {
16
+ this.#resolution = resolution;
17
+
18
+
19
+ //max mip
20
+ const mip_level = Math.log2(resolution);
21
+
22
+ compose_tile_address(mip_level, 0, 0);
23
+
24
+ this.#pyramid = new Uint32Array(mip_level);
25
+ }
26
+
27
+ get resolution() {
28
+ return this.#resolution;
29
+ }
30
+
31
+ /**
32
+ *
33
+ * @param {PageTexture} page
34
+ */
35
+ set residency(page) {
36
+
37
+ const tiles = page.resident_tiles;
38
+ const tile_count = tiles.length;
39
+
40
+ for (let i = 0; i < tile_count; i++) {
41
+ const tile = tiles[i];
42
+ }
43
+
44
+ }
45
+
46
+ }
@@ -5,9 +5,12 @@ import { AssetManager } from "../../../../asset/AssetManager.js";
5
5
  import { GameAssetType } from "../../../../asset/GameAssetType.js";
6
6
  import { compose_finger_print } from "./tile/compose_finger_print.js";
7
7
  import { decompose_finger_print } from "./tile/decompose_finger_print.js";
8
- import { TextureTile } from "./tile/TextureTile.js";
8
+ import { VirtualTextureTile } from "./tile/VirtualTextureTile.js";
9
9
 
10
- export class TileLoader {
10
+ /**
11
+ * Facilitates prioritized queueing and loading of individual texture tiles
12
+ */
13
+ export class VirtualTextureTileLoader {
11
14
  /**
12
15
  * Where the tiles are stored
13
16
  * @type {string}
@@ -38,7 +41,7 @@ export class TileLoader {
38
41
  * How many tiles can be loaded at the same time
39
42
  * @type {number}
40
43
  */
41
- #concurrency = 2;
44
+ #concurrency = 4;
42
45
 
43
46
  /**
44
47
  * Tiles that are currently being loaded
@@ -59,7 +62,7 @@ export class TileLoader {
59
62
  */
60
63
  on = {
61
64
  /**
62
- * @type {Signal<TextureTile>}
65
+ * @type {Signal<VirtualTextureTile>}
63
66
  */
64
67
  loaded: new Signal()
65
68
  };
@@ -127,7 +130,7 @@ export class TileLoader {
127
130
 
128
131
  /**
129
132
  *
130
- * @param {UsageMetadata} usage
133
+ * @param {VirtualTextureUsage} usage
131
134
  */
132
135
  #sort_queue_by_usage(usage) {
133
136
 
@@ -147,7 +150,7 @@ export class TileLoader {
147
150
 
148
151
  /**
149
152
  *
150
- * @param {UsageMetadata} usage
153
+ * @param {VirtualTextureUsage} usage
151
154
  */
152
155
  update_usage(usage) {
153
156
  this.#sort_queue_by_usage(usage);
@@ -192,7 +195,7 @@ export class TileLoader {
192
195
  * @param {number} mip
193
196
  * @param {number} x
194
197
  * @param {number} y
195
- * @returns {Promise<TextureTile>}
198
+ * @returns {Promise<VirtualTextureTile>}
196
199
  */
197
200
  #load(mip, x, y) {
198
201
  const file_name = this.#build_file_name(mip, x, y);
@@ -206,7 +209,7 @@ export class TileLoader {
206
209
 
207
210
  const sampler = asset.create();
208
211
 
209
- const tile = new TextureTile();
212
+ const tile = new VirtualTextureTile();
210
213
 
211
214
 
212
215
  tile.data = sampler;
@@ -1,15 +1,9 @@
1
1
  import { arrayQuickSort } from "../../../../../core/collection/array/arrayQuickSort.js";
2
- import { compose_finger_print } from "./tile/compose_finger_print.js";
2
+ import { compose_tile_address } from "./tile/compose_tile_address.js";
3
3
  import { finger_print_to_tile_address } from "./tile/finger_print_to_tile_address.js";
4
4
 
5
5
 
6
- function compose_tile_address(mip, x, y) {
7
- const finger_print = compose_finger_print(mip, x, y);
8
-
9
- return finger_print_to_tile_address(finger_print);
10
- }
11
-
12
- export class UsageMetadata {
6
+ export class VirtualTextureUsage {
13
7
 
14
8
  #counts_intrinsic = new Uint32Array(0);
15
9
  /**
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ClampToEdgeWrapping,
3
+ DoubleSide,
3
4
  GLSL3,
4
5
  Matrix4,
5
6
  NearestFilter,
@@ -18,8 +19,8 @@ import { max2 } from "../../../../../core/math/max2.js";
18
19
  import { generate_halton_jitter } from "../../../generate_halton_jitter.js";
19
20
  import { renderScreenSpace } from "../../../render/utils/renderScreenSpace.js";
20
21
  import { Sampler2D } from "../../sampler/Sampler2D.js";
21
- import { fragment, vertex } from "./ShaderUsage.js";
22
- import { UsageMetadata } from "./UsageMetadata.js";
22
+ import { VirtualTextureUsage } from "./VirtualTextureUsage.js";
23
+ import { fragment, vertex } from "./VirtualTextureUsageShader.js";
23
24
 
24
25
  const usage_material_uniforms = {
25
26
  "u_mt_params": { value: new Vector2(0.1, 1) },
@@ -40,6 +41,7 @@ const usage_material = new RawShaderMaterial({
40
41
  uniforms: usage_material_uniforms,
41
42
  vertexShader: vertex(),
42
43
  fragmentShader: fragment(),
44
+ side: DoubleSide,
43
45
  glslVersion: GLSL3
44
46
 
45
47
  });
@@ -69,7 +71,7 @@ const clear_usage_material = new RawShaderMaterial({
69
71
 
70
72
  const scratch_matrix = new Float32Array(16);
71
73
 
72
- export class VirtualTextureManager {
74
+ export class VirtualTextureUsageUpdater {
73
75
 
74
76
  #frame_index = 0;
75
77
 
@@ -79,7 +81,7 @@ export class VirtualTextureManager {
79
81
  */
80
82
  #frame_jitter_offsets = new Float32Array([0, 0]);
81
83
  #frame_jitter_samples = 1;
82
- #frame_jitter_enabled = true;
84
+ #frame_jitter_enabled = false;
83
85
 
84
86
  #initialize_frame_jitter() {
85
87
  this.#frame_jitter_samples = this.#usage_resolution_scale;
@@ -109,7 +111,7 @@ export class VirtualTextureManager {
109
111
  */
110
112
  #usage_resolution_scale = 32;
111
113
 
112
- #usage_metadata = new UsageMetadata();
114
+ #usage_metadata = new VirtualTextureUsage();
113
115
 
114
116
  #texture_id = 3;
115
117
  #texture_resolution = 65536;
@@ -6,22 +6,28 @@ import { sampler2d_write_to_canvas_raw } from "../../../sampler/sampler2d_write_
6
6
  export class ResidencyDebugView extends EmptyView {
7
7
  /**
8
8
  *
9
- * @type {SparseTexture|null}
9
+ * @type {PageTexture|null}
10
10
  */
11
11
  texture = null;
12
12
 
13
13
  #canvas = new CanvasView();
14
14
 
15
+ #previous_residency = new Uint32Array(1024);
16
+
15
17
  constructor() {
16
18
  super({
17
19
  css: {
18
- position: "absolute"
20
+ position: "absolute",
21
+ boxShadow: "0 0 8px black",
22
+ background: "black"
19
23
  }
20
24
  });
21
25
 
22
26
  this.#canvas.css(CSS_ABSOLUTE_POSITIONING);
23
27
 
24
28
  this.addChild(this.#canvas);
29
+
30
+ this.#previous_residency.fill(-1);
25
31
  }
26
32
 
27
33
  update() {
@@ -47,12 +53,18 @@ export class ResidencyDebugView extends EmptyView {
47
53
  for (let i = 0; i < residentTiles.length; i++) {
48
54
  const tile = residentTiles[i];
49
55
 
50
- sampler2d_write_to_canvas_raw(tile.data, temp.el);
56
+ const page_slot = tile.page_slot;
57
+ if (this.#previous_residency[page_slot] === tile.finder_print) {
58
+ continue;
59
+ }
51
60
 
52
- const column = tile.page_slot % tile_columns;
53
- const row = (tile.page_slot / tile_columns) | 0;
61
+ sampler2d_write_to_canvas_raw(tile.data, temp.el);
62
+ const column = page_slot % tile_columns;
63
+ const row = (page_slot / tile_columns) | 0;
54
64
 
55
65
  canvas.context2d.drawImage(temp.el, 0, 0, tile_resolution, tile_resolution, tile_resolution * column, tile_resolution * row, tile_resolution, tile_resolution);
66
+
67
+ this.#previous_residency[page_slot] = tile.finder_print;
56
68
  }
57
69
  }
58
70
  }
@@ -31,7 +31,7 @@ export class UsageDebugView extends EmptyView {
31
31
 
32
32
  /**
33
33
  *
34
- * @param {UsageMetadata} usage
34
+ * @param {VirtualTextureUsage} usage
35
35
  */
36
36
  set usage(usage) {
37
37
 
@@ -191,7 +191,7 @@ export class UsagePyramidDebugView extends EmptyView {
191
191
 
192
192
  /**
193
193
  *
194
- * @param {UsageMetadata} usage
194
+ * @param {VirtualTextureUsage} usage
195
195
  */
196
196
  set usage(usage) {
197
197