@woosh/meep-engine 2.73.0 → 2.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/meep.cjs +185 -189
  3. package/build/meep.min.js +1 -1
  4. package/build/meep.module.js +185 -189
  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 +64 -0
  14. package/src/core/collection/SCRATCH_UINT32_TRAVERSAL_STACK.js +1 -0
  15. package/src/core/geom/3d/aabb/aabb3_signed_distance_sqr_to_point.js +1 -0
  16. package/src/core/geom/3d/aabb/aabb3_unsigned_distance_sqr_to_point.js +36 -0
  17. package/src/core/process/worker/OnDemandWorkerManager.js +5 -1
  18. package/src/engine/asset/loaders/ArrayBufferLoader.js +13 -15
  19. package/src/engine/asset/loaders/image/ImageDecoderWorker.js +1 -1
  20. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +5 -7
  21. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
  22. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +5 -6
  23. package/src/engine/asset/loaders/image/png/PNG.js +339 -332
  24. package/src/engine/asset/loaders/image/png/PNGReader.js +77 -30
  25. package/src/engine/asset/loaders/image/png/prototypePNG.js +13 -4
  26. package/src/engine/graphics/generate_halton_jitter.js +21 -0
  27. package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +3 -20
  28. package/src/engine/graphics/texture/virtual/v2/PageTexture.js +335 -0
  29. package/src/engine/graphics/texture/virtual/v2/ResidentTileTexture.js +46 -0
  30. package/src/engine/graphics/texture/virtual/v2/{TileLoader.js → VirtualTextureTileLoader.js} +33 -13
  31. package/src/engine/graphics/texture/virtual/v2/{UsageMetadata.js → VirtualTextureUsage.js} +68 -22
  32. package/src/engine/graphics/texture/virtual/v2/{VirtualTextureManager.js → VirtualTextureUsageUpdater.js} +66 -9
  33. package/src/engine/graphics/texture/virtual/v2/debug/ResidencyDebugView.js +70 -0
  34. package/src/engine/graphics/texture/virtual/v2/debug/UsageDebugView.js +63 -0
  35. package/src/engine/graphics/texture/virtual/v2/{UsagePyramidDebugView.js → debug/UsagePyramidDebugView.js} +31 -40
  36. package/src/engine/graphics/texture/virtual/v2/prototype.js +98 -54
  37. package/src/engine/graphics/texture/virtual/v2/{TextureTile.js → tile/VirtualTextureTile.js} +3 -3
  38. package/src/engine/graphics/texture/virtual/v2/tile/compose_finger_print.js +23 -0
  39. package/src/engine/graphics/texture/virtual/v2/tile/compose_tile_address.js +26 -0
  40. package/src/engine/graphics/texture/virtual/v2/tile/decompose_finger_print.js +12 -0
  41. package/src/engine/graphics/texture/virtual/v2/tile/finger_print_to_tile_address.js +16 -0
  42. package/src/engine/graphics/texture/virtual/v2/{tile_index_to_finger_print.js → tile/tile_address_to_finger_print.js} +7 -3
  43. package/src/view/CSS_ABSOLUTE_POSITIONING.js +5 -0
  44. package/src/engine/graphics/texture/virtual/v2/SparseTexture.js +0 -182
  45. package/src/engine/graphics/texture/virtual/v2/UsageDebugView.js +0 -64
  46. package/src/engine/graphics/texture/virtual/v2/compose_finger_print.js +0 -13
  47. package/src/engine/graphics/texture/virtual/v2/finger_print_to_tile_index.js +0 -37
  48. /package/src/engine/graphics/texture/virtual/v2/{ShaderUsage.js → VirtualTextureUsageShader.js} +0 -0
@@ -1,12 +1,9 @@
1
- import { assert } from "../../../../../core/assert.js";
2
- import LabelView from "../../../../../view/common/LabelView.js";
3
- import EmptyView from "../../../../../view/elements/EmptyView.js";
4
-
5
- const ABSOLUTE_CSS = {
6
- position: "absolute",
7
- top: 0,
8
- left: 0
9
- };
1
+ import { assert } from "../../../../../../core/assert.js";
2
+ import LabelView from "../../../../../../view/common/LabelView.js";
3
+ import { CSS_ABSOLUTE_POSITIONING } from "../../../../../../view/CSS_ABSOLUTE_POSITIONING.js";
4
+ import EmptyView from "../../../../../../view/elements/EmptyView.js";
5
+ import { decompose_finger_print } from "../tile/decompose_finger_print.js";
6
+ import { tile_address_to_finger_print } from "../tile/tile_address_to_finger_print.js";
10
7
 
11
8
  class TextureLODView extends EmptyView {
12
9
 
@@ -22,7 +19,7 @@ class TextureLODView extends EmptyView {
22
19
  resolution = [1, 1],
23
20
  tile_size = 8
24
21
  }) {
25
- super({ css: ABSOLUTE_CSS });
22
+ super({ css: CSS_ABSOLUTE_POSITIONING });
26
23
 
27
24
  this.css({
28
25
  background: "rgba(255,255,255,0.05)"
@@ -38,10 +35,11 @@ class TextureLODView extends EmptyView {
38
35
 
39
36
  for (let j = 0; j < height; j++) {
40
37
  for (let i = 0; i < width; i++) {
41
- const tileView = new EmptyView({ css: ABSOLUTE_CSS });
38
+ const tileView = new EmptyView({ css: CSS_ABSOLUTE_POSITIONING });
42
39
 
43
40
  // const flipped_y = height - j - 1;
44
41
  tileView.position.set(i * tile_size, j * tile_size);
42
+ // tileView.position.set(i * tile_size, flipped_y * tile_size);
45
43
  tileView.size.set(tile_size, tile_size);
46
44
 
47
45
  this.clearTile(tileView);
@@ -57,7 +55,7 @@ class TextureLODView extends EmptyView {
57
55
 
58
56
  const label = new LabelView(`${width} x ${height}`, {
59
57
  css: {
60
- ...ABSOLUTE_CSS,
58
+ ...CSS_ABSOLUTE_POSITIONING,
61
59
  color: '#FFFFFF',
62
60
  textShadow: '0 0 2px black',
63
61
  whiteSpace: "pre"
@@ -193,17 +191,14 @@ export class UsagePyramidDebugView extends EmptyView {
193
191
 
194
192
  /**
195
193
  *
196
- * @param {UsageMetadata} usage
194
+ * @param {VirtualTextureUsage} usage
197
195
  */
198
196
  set usage(usage) {
199
197
 
200
198
  for (let i = 0; i < this.#used_set_size; i++) {
201
199
  const finger_print = this.#used_set[i];
202
200
 
203
-
204
- const mip = (finger_print >> 24) & 0xFF;
205
- const x = (finger_print >> 16) & 0xFF;
206
- const y = (finger_print >> 8) & 0xFF;
201
+ const { mip, x, y } = decompose_finger_print(finger_print);
207
202
 
208
203
  const mipView = this.#levels[mip];
209
204
 
@@ -214,38 +209,34 @@ export class UsagePyramidDebugView extends EmptyView {
214
209
  this.#used_set_size = 0;
215
210
 
216
211
 
217
- const mip_count = this.#levels.length;
212
+ const occupancy = usage.occupancy;
213
+ const occupancyCount = usage.occupancy_count;
218
214
 
219
- for (let mip = 0; mip < mip_count; mip++) {
220
- const size = 1 << mip;
215
+ for (let i = 0; i < occupancyCount; i++) {
216
+ const occupancy_index = occupancy[i];
217
+ const fingerPrint = tile_address_to_finger_print(occupancy_index);
221
218
 
222
- for (let y = 0; y < size; y++) {
223
- for (let x = 0; x < size; x++) {
224
- const count = usage.getCountBy(mip,x,y);
219
+ const count = usage.getCountByFingerprint(fingerPrint);
220
+
221
+ if (count <= 0) {
222
+ continue;
223
+ }
225
224
 
226
- if(count === 0){
227
- continue;
228
- }
225
+ const { mip, x, y } = decompose_finger_print(fingerPrint);
229
226
 
230
- const mipView = this.#levels[mip];
231
227
 
232
- const tile = mipView.getTile(x, y);
228
+ const mipView = this.#levels[mip];
233
229
 
234
- tile.css({
235
- background: "rgba(255,0,0,0.8)"
236
- });
230
+ const tile = mipView.getTile(x, y);
237
231
 
238
- tile.visible = true;
232
+ tile.css({
233
+ background: "rgba(255,0,0,0.8)"
234
+ });
239
235
 
240
- const finger_print = (mip << 24)
241
- | (x << 16)
242
- | (y << 8)
243
- ;
236
+ tile.visible = true;
244
237
 
245
- this.#used_set[this.#used_set_size] = finger_print;
246
- this.#used_set_size++;
247
- }
248
- }
238
+ this.#used_set[this.#used_set_size] = fingerPrint;
239
+ this.#used_set_size++;
249
240
  }
250
241
 
251
242
  }
@@ -3,12 +3,14 @@ import {
3
3
  AmbientLight,
4
4
  Clock,
5
5
  DirectionalLight,
6
+ DoubleSide,
7
+ Matrix4,
6
8
  Mesh,
7
- MeshStandardMaterial,
9
+ MeshBasicMaterial,
8
10
  PerspectiveCamera,
11
+ PlaneBufferGeometry,
9
12
  Scene,
10
13
  TextureLoader,
11
- TorusGeometry,
12
14
  Vector2,
13
15
  WebGLRenderer
14
16
  } from "three";
@@ -18,9 +20,11 @@ import EmptyView from "../../../../../view/elements/EmptyView.js";
18
20
  import { AssetManager } from "../../../../asset/AssetManager.js";
19
21
  import { GameAssetType } from "../../../../asset/GameAssetType.js";
20
22
  import { ImageRGBADataLoader } from "../../../../asset/loaders/image/ImageRGBADataLoader.js";
21
- import { SparseTexture } from "./SparseTexture.js";
22
- import { UsageDebugView } from "./UsageDebugView.js";
23
- import { VirtualTextureManager } from "./VirtualTextureManager.js";
23
+ import { ResidencyDebugView } from "./debug/ResidencyDebugView.js";
24
+ import { UsageDebugView } from "./debug/UsageDebugView.js";
25
+ import { UsagePyramidDebugView } from "./debug/UsagePyramidDebugView.js";
26
+ import { PageTexture } from "./PageTexture.js";
27
+ import { VirtualTextureUsageUpdater } from "./VirtualTextureUsageUpdater.js";
24
28
 
25
29
  let camera,
26
30
  /**
@@ -35,61 +39,102 @@ let camera,
35
39
 
36
40
  let mesh;
37
41
 
38
- const am = new AssetManager();
39
- am.registerLoader(GameAssetType.Image, new ImageRGBADataLoader());
40
- am.startup();
41
-
42
- const virtualTextureManager = new VirtualTextureManager();
43
- virtualTextureManager.setTextureParameters(
44
- // 2048,
45
- 16384,
46
- 128,
47
- 3
48
- );
49
-
50
- const sparseTexture = new SparseTexture();
51
- sparseTexture.page_texture_size = [1024, 1024];
52
- sparseTexture.tile_resolution = virtualTextureManager.tile_resolution;
53
- sparseTexture.asset_manager = am;
54
-
55
- console.log(sparseTexture);
56
-
57
- // const TEXTURE_URL = "data/textures/utility/uv_map_reference.png";
42
+ const TEXTURE_URL = "data/textures/utility/uv_map_reference.png";
58
43
  // const TEXTURE_URL = "data/textures/utility/4096x4096TexelDensityTexture1.png";
59
44
  // const TEXTURE_URL = "data/textures/utility/Lenna.png";
60
45
  // const TEXTURE_URL = "data/textures/utility/TESTIMAGES/SAMPLING/8BIT/RGB/2448x2448/SRC/img_2448x2448_3x8bit_SRC_RGB_cards_a.png";
61
- const TEXTURE_URL = "data/models/LowPolyTownshipSet/Town_Hall//diffuse_2048.png";
62
-
63
- const container_view = new EmptyView();
64
- //
65
- const usageDebugView = new UsageDebugView();
66
- usageDebugView.mip_levels = virtualTextureManager.max_mip_level;
67
- container_view.addChild(usageDebugView);
46
+ // const TEXTURE_URL = "data/models/LowPolyTownshipSet/Town_Hall//diffuse_2048.png";
68
47
 
48
+ const virtualTextureManager = new VirtualTextureUsageUpdater();
49
+ const sparseTexture = new PageTexture();
50
+ const residencyDebugView = new ResidencyDebugView();
69
51
 
70
- // const usagePyramidDebugView = new UsagePyramidDebugView();
71
- // usagePyramidDebugView.setImageURL(TEXTURE_URL);
72
- //
73
- // container_view.addChild(usagePyramidDebugView);
52
+ const container_view = new EmptyView();
74
53
 
75
54
  const options = {
76
- spin: true
55
+ spin: false
77
56
  };
78
57
 
79
58
  init();
80
- animate();
81
59
 
82
-
83
- function makeTorus() {
60
+ function makeMesh() {
84
61
  const size = 0.65;
85
- mesh = new Mesh(new TorusGeometry(size, 0.3, 30, 30), new MeshStandardMaterial({
86
- roughness: 0.4,
87
- map: new TextureLoader().load(TEXTURE_URL)
62
+
63
+ const map = new TextureLoader().load(TEXTURE_URL);
64
+ map.flipY = false;
65
+
66
+ // const geo = new TetrahedronBufferGeometry(size,30);
67
+ // const geo = new TorusGeometry(size, 0.3, 30, 30);
68
+ const geo = new PlaneBufferGeometry(size, size);
69
+
70
+ mesh = new Mesh(geo, new MeshBasicMaterial({
71
+ map,
72
+ side: DoubleSide
88
73
  }));
89
- mesh.rotation.x = 0.3;
74
+ const m4 = new Matrix4();
75
+
76
+ // m4.makeRotationZ(-Math.PI/2);
77
+ m4.makeScale(1, -1, -1);
78
+
79
+ geo.applyMatrix4(m4);
80
+
81
+ // mesh.rotation.x = 0.3;
82
+
83
+ scene.add(mesh);
90
84
  }
91
85
 
92
- function init() {
86
+ function makeGLTF(path) {
87
+
88
+ new GLTFLoader().load(path, (gltf) => {
89
+
90
+ mesh = gltf.scene;
91
+ scene.add(mesh);
92
+
93
+ });
94
+ }
95
+
96
+ async function init() {
97
+
98
+ const am = new AssetManager();
99
+ await am.registerLoader(GameAssetType.Image, new ImageRGBADataLoader());
100
+ am.startup();
101
+
102
+ virtualTextureManager.setTextureParameters(
103
+ 2048,
104
+ // 16384,
105
+ 32,
106
+ 3
107
+ );
108
+
109
+ sparseTexture.path = "data/textures/utility/vt/uv_map_reference";
110
+ // sparseTexture.path = "data/textures/utility/vt/Lenna";
111
+ // sparseTexture.path = "data/textures/utility/vt/TexelDensity1";
112
+ sparseTexture.page_texture_size = [128, 768];
113
+ sparseTexture.tile_resolution = virtualTextureManager.tile_resolution;
114
+ sparseTexture.asset_manager = am;
115
+
116
+
117
+ console.log(sparseTexture);
118
+
119
+
120
+ //
121
+ const usageDebugView = new UsageDebugView();
122
+ usageDebugView.mip_levels = virtualTextureManager.max_mip_level;
123
+ // container_view.addChild(usageDebugView);
124
+
125
+
126
+ const usagePyramidDebugView = new UsagePyramidDebugView();
127
+ usagePyramidDebugView.setImageURL(TEXTURE_URL);
128
+ container_view.addChild(usagePyramidDebugView);
129
+
130
+ residencyDebugView.texture = sparseTexture;
131
+ residencyDebugView.css({
132
+ bottom: 0,
133
+ right: 0
134
+ });
135
+ container_view.addChild(residencyDebugView);
136
+
137
+ // ===================
93
138
 
94
139
  const container = document.body;
95
140
 
@@ -98,20 +143,17 @@ function init() {
98
143
  container.appendChild(container_view.el);
99
144
  container_view.link();
100
145
 
101
- camera = new PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 300);
146
+ camera = new PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 100);
102
147
  camera.position.z = 4;
103
148
 
104
149
  scene = new Scene();
105
150
 
106
151
  clock = new Clock();
107
152
 
153
+ // makeTorus();
154
+ makeMesh();
108
155
 
109
- new GLTFLoader().load("data/models/LowPolyTownshipSet/Town_Hall/model.gltf", (gltf) => {
110
-
111
- mesh = gltf.scene;
112
- scene.add(mesh);
113
-
114
- });
156
+ // makeGLTF("data/models/LowPolyTownshipSet/Town_Hall/model.gltf");
115
157
 
116
158
  scene.add(new DirectionalLight(0xFFFFFF, 0.7));
117
159
  scene.add(new AmbientLight(0xFFFFFF, 0.2));
@@ -143,7 +185,7 @@ function init() {
143
185
  gui.add(options, key);
144
186
  });
145
187
 
146
-
188
+ animate();
147
189
  }
148
190
 
149
191
  function onWindowResize() {
@@ -185,8 +227,10 @@ function render() {
185
227
  renderer.clear();
186
228
  renderer.render(scene, camera)
187
229
 
188
- usageDebugView.usage = virtualTextureManager.usage_metadata;
230
+ // usageDebugView.usage = virtualTextureManager.usage_metadata;
189
231
 
190
232
  // usagePyramidDebugView.setTextureParameters(virtualTextureManager.texture_resolution, virtualTextureManager.tile_resolution);
191
233
  // usagePyramidDebugView.usage = virtualTextureManager.usage_metadata;
234
+
235
+ residencyDebugView.update();
192
236
  }
@@ -1,4 +1,4 @@
1
- export class TextureTile {
1
+ export class VirtualTextureTile {
2
2
 
3
3
  finder_print = 0;
4
4
 
@@ -8,7 +8,7 @@ export class TextureTile {
8
8
  * Currently occupied page slot, only valid when page is resident
9
9
  * @type {number}
10
10
  */
11
- page_slot = 0;
11
+ page_slot = -1;
12
12
 
13
13
  /**
14
14
  *
@@ -18,7 +18,7 @@ export class TextureTile {
18
18
 
19
19
  /**
20
20
  *
21
- * @param {TextureTile} other
21
+ * @param {VirtualTextureTile} other
22
22
  * @returns {boolean}
23
23
  */
24
24
  equals(other) {
@@ -0,0 +1,23 @@
1
+ import { assert } from "../../../../../../core/assert.js";
2
+
3
+ /**
4
+ *
5
+ * @param {number} mip
6
+ * @param {number} x
7
+ * @param {number} y
8
+ * @returns {number}
9
+ */
10
+ export function compose_finger_print(mip, x, y) {
11
+ // validate
12
+ assert.isNonNegativeInteger(x, 'x');
13
+ assert.isNonNegativeInteger(y, 'y');
14
+ assert.isNonNegativeInteger(mip, 'mip');
15
+
16
+ assert.lessThan(x, (1 << mip), 'x');
17
+ assert.lessThan(y, (1 << mip), 'y');
18
+
19
+ return (mip << 24)
20
+ | (x << 16)
21
+ | (y << 8)
22
+ ;
23
+ }
@@ -0,0 +1,26 @@
1
+ import { assert } from "../../../../../../core/assert.js";
2
+ import { split_by_2 } from "../../../../../../core/geom/3d/morton/split_by_2.js";
3
+
4
+ /**
5
+ *
6
+ * @param {number} mip
7
+ * @param {number} x
8
+ * @param {number} y
9
+ * @returns {number}
10
+ */
11
+ export function compose_tile_address(mip, x, y) {
12
+
13
+ // figure out resolution of this mip level
14
+ const mip_resolution = 1 << mip;
15
+
16
+ assert.lessThan(x, mip_resolution);
17
+ assert.lessThan(y, mip_resolution);
18
+
19
+ // this is basically converting something like 0100 to 0011;
20
+ const mip_mask = mip_resolution - 1;
21
+
22
+ // where data for this mip starts
23
+ const index_offset = split_by_2(mip_mask);
24
+
25
+ return index_offset + x + y * mip_resolution;
26
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ *
3
+ * @param {number} finger_print
4
+ * @returns {{mip: number, x: number, y: number}}
5
+ */
6
+ export function decompose_finger_print(finger_print) {
7
+ const mip = (finger_print >> 24) & 0xFF;
8
+ const x = (finger_print >> 16) & 0xFF;
9
+ const y = (finger_print >> 8) & 0xFF;
10
+
11
+ return { mip, x, y };
12
+ }
@@ -0,0 +1,16 @@
1
+ import { compose_tile_address } from "./compose_tile_address.js";
2
+
3
+ /**
4
+ *
5
+ * @param {number} finger_print
6
+ * @returns {number}
7
+ */
8
+ export function finger_print_to_tile_address(finger_print) {
9
+ // decode fingerprint
10
+ const mip = (finger_print >> 24) & 0xFF;
11
+ const x = (finger_print >> 16) & 0xFF;
12
+ const y = (finger_print >> 8) & 0xFF;
13
+
14
+ return compose_tile_address(mip, x, y);
15
+ }
16
+
@@ -1,4 +1,4 @@
1
- import { split_by_2 } from "../../../../../core/geom/3d/morton/split_by_2.js";
1
+ import { split_by_2 } from "../../../../../../core/geom/3d/morton/split_by_2.js";
2
2
  import { compose_finger_print } from "./compose_finger_print.js";
3
3
 
4
4
  /**
@@ -6,7 +6,7 @@ import { compose_finger_print } from "./compose_finger_print.js";
6
6
  * @param {number} index
7
7
  * @returns {number}
8
8
  */
9
- export function tile_index_to_finger_print(index) {
9
+ export function tile_address_to_finger_print(index) {
10
10
  for (let mip = 0; mip < 99; mip++) {
11
11
  const resolution = 1 << mip;
12
12
 
@@ -14,7 +14,11 @@ export function tile_index_to_finger_print(index) {
14
14
 
15
15
  const index_offset = split_by_2(mip_mask);
16
16
 
17
- if (index > index_offset) {
17
+ const next_mip_mask = mip_mask << 1 | 0x1;
18
+
19
+ const index_offset_next = split_by_2(next_mip_mask);
20
+
21
+ if (index >= index_offset_next) {
18
22
  continue;
19
23
  }
20
24
 
@@ -0,0 +1,5 @@
1
+ export const CSS_ABSOLUTE_POSITIONING = Object.freeze({
2
+ position: "absolute",
3
+ top: 0,
4
+ left: 0
5
+ });
@@ -1,182 +0,0 @@
1
- import { WebGLRenderTarget } from "three";
2
- import { BitSet } from "../../../../../core/binary/BitSet.js";
3
- import { Cache } from "../../../../../core/cache/Cache.js";
4
- import { array_copy } from "../../../../../core/collection/array/array_copy.js";
5
- import { passThrough, strictEquals } from "../../../../../core/function/Functions.js";
6
- import { compose_finger_print } from "./compose_finger_print.js";
7
- import { TileLoader } from "./TileLoader.js";
8
-
9
- /**
10
- * How much extra data to store in cache (in bytes)
11
- * @type {number}
12
- */
13
- const DEFAULT_CACHE_SIZE = 16 * 1024 * 1024;
14
-
15
- export class SparseTexture {
16
- #page_texture = new WebGLRenderTarget(1, 1);
17
-
18
- #page_texture_size = [1, 1];
19
-
20
- /**
21
- *
22
- * @type {TextureTile[]}
23
- */
24
- #resident_tiles = [];
25
-
26
- #page_slot_occupancy = new BitSet();
27
-
28
- #tile_resolution = 128;
29
-
30
- #residency_tile_capacity = 0;
31
-
32
- #loader = new TileLoader();
33
-
34
- /**
35
- *
36
- * @type {AssetManager|null}
37
- */
38
- #asset_manager = null;
39
-
40
- set asset_manager(v) {
41
- this.#asset_manager = v
42
-
43
- this.#loader.asset_manager = v;
44
- }
45
-
46
- #update_residency_capacity() {
47
- const tile_resolution = this.#tile_resolution;
48
- const size = this.#page_texture_size;
49
-
50
- const x = size[0] / tile_resolution;
51
- const y = size[1] / tile_resolution;
52
-
53
- this.#residency_tile_capacity = x * y;
54
- }
55
-
56
-
57
- /**
58
- *
59
- * @param {number} v
60
- */
61
- set tile_resolution(v) {
62
- this.#tile_resolution = v;
63
-
64
- this.#update_residency_capacity();
65
- }
66
-
67
- /**
68
- * Tiles that are not currently resident live here
69
- * key is the tile's "fingerprint"
70
- * @type {Cache<number,TextureTile>}
71
- */
72
- #tile_cache = new Cache({
73
- keyHashFunction: passThrough,
74
- keyEqualityFunction: strictEquals,
75
- maxWeight: DEFAULT_CACHE_SIZE,
76
- valueWeigher: () => this.#tile_resolution * this.#tile_resolution * 4
77
- });
78
-
79
- #find_eviction_target_index() {
80
- // find least-recently used
81
- const tiles = this.#resident_tiles;
82
- const count = tiles.length;
83
-
84
- let max = -1;
85
- let max_index = -1;
86
-
87
- for (let i = 0; i < count; i++) {
88
- const tile = tiles[i];
89
-
90
- if (tile.last_used_time > max) {
91
- max = tile.last_used_time;
92
- max_index = i;
93
- }
94
- }
95
-
96
- return max_index;
97
- }
98
-
99
- #evict_one() {
100
- const index = this.#find_eviction_target_index();
101
-
102
- if (index === -1) {
103
- return false;
104
- }
105
-
106
- return this.#remove_resident_tile(index);
107
- }
108
-
109
- /**
110
- *
111
- * @param {number} index
112
- * @returns {boolean}
113
- */
114
- #remove_resident_tile(index) {
115
- const [removed] = this.#resident_tiles.splice(index, 1);
116
-
117
- const pageSlot = removed.page_slot;
118
-
119
- // mark slot as empty for next tile
120
- this.#page_slot_occupancy.clear(pageSlot);
121
-
122
- // push into cache
123
- this.#tile_cache.put(removed.finder_print, removed);
124
-
125
- return true;
126
- }
127
-
128
- /**
129
- *
130
- * @param {number[]} v
131
- */
132
- set page_texture_size(v) {
133
- array_copy(
134
- v, 0,
135
- this.#page_texture_size, 0,
136
- 2
137
- );
138
-
139
- this.#page_texture.dispose();
140
- this.#page_texture.setSize(this.#page_texture[0], this.#page_texture[1]);
141
-
142
- this.#update_residency_capacity();
143
- }
144
-
145
- /**
146
- *
147
- * @param {UsageMetadata} usage
148
- */
149
- update_usage(usage) {
150
- const max_mip = usage.max_mip_level;
151
-
152
- for (let mip = 0; mip < max_mip; mip++) {
153
-
154
- const resolution = 1 << mip;
155
-
156
- for (let y = 0; y < resolution; y++) {
157
- for (let x = 0; x < resolution; x++) {
158
-
159
- const count = usage.getCountBy(mip, x, y);
160
-
161
- if (count === 0) {
162
- continue;
163
- }
164
-
165
- const fingerprint = compose_finger_print(mip, x, y);
166
-
167
- this.#loader.enqueue(fingerprint);
168
-
169
- }
170
- }
171
-
172
- }
173
-
174
- this.#loader.update_usage(usage);
175
- }
176
-
177
- dispose() {
178
- this.#page_texture.dispose();
179
- this.#tile_cache.clear();
180
- this.#page_slot_occupancy.reset();
181
- }
182
- }