@woosh/meep-engine 2.72.0 → 2.74.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.
- package/build/bundle-worker-image-decoder.js +1 -1
- package/build/meep.cjs +38 -189
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +38 -189
- package/package.json +3 -2
- package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
- package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +4 -5
- package/src/engine/asset/loaders/image/png/PNGReader.js +23 -19
- package/src/engine/graphics/ecs/camera/FrustumProjector.js +31 -182
- package/src/engine/graphics/generate_halton_jitter.js +21 -0
- package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +3 -20
- package/src/engine/graphics/texture/virtual/v2/NOTES.md +11 -1
- package/src/engine/graphics/texture/virtual/v2/ShaderUsage.js +7 -5
- package/src/engine/graphics/texture/virtual/v2/SparseTexture.js +291 -0
- package/src/engine/graphics/texture/virtual/v2/TileLoader.js +232 -0
- package/src/engine/graphics/texture/virtual/v2/UsageMetadata.js +118 -134
- package/src/engine/graphics/texture/virtual/v2/VirtualTextureManager.js +73 -9
- package/src/engine/graphics/texture/virtual/v2/debug/ResidencyDebugView.js +58 -0
- package/src/engine/graphics/texture/virtual/v2/debug/UsageDebugView.js +63 -0
- package/src/engine/graphics/texture/virtual/v2/{UsagePyramidDebugView.js → debug/UsagePyramidDebugView.js} +27 -23
- package/src/engine/graphics/texture/virtual/v2/prototype.js +62 -19
- package/src/engine/graphics/texture/virtual/v2/tile/TextureTile.js +31 -0
- package/src/engine/graphics/texture/virtual/v2/tile/compose_finger_print.js +23 -0
- package/src/engine/graphics/texture/virtual/v2/tile/compose_tile_address.js +22 -0
- package/src/engine/graphics/texture/virtual/v2/tile/decompose_finger_print.js +12 -0
- package/src/engine/graphics/texture/virtual/v2/tile/finger_print_to_tile_address.js +16 -0
- package/src/engine/graphics/texture/virtual/v2/tile/tile_address_to_finger_print.js +35 -0
- package/src/view/CSS_ABSOLUTE_POSITIONING.js +5 -0
- package/src/engine/graphics/clouds/MaterialTransformer.js +0 -0
- package/src/engine/graphics/clouds/TerrainCloudsPlugin.js +0 -0
- package/src/engine/graphics/clouds/cs_build_fragment_shader.js +0 -0
- package/src/engine/graphics/clouds/cs_build_vertex_shader.js +0 -0
- package/src/engine/graphics/ecs/camera/TiltCameraController.js +0 -69
- package/src/engine/graphics/ecs/camera/is_valid_distance_value.js +0 -11
- package/src/engine/graphics/texture/virtual/v2/UsageDebugView.js +0 -51
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { assert } from "../../../../../core/assert.js";
|
|
2
|
+
import { arrayQuickSort } from "../../../../../core/collection/array/arrayQuickSort.js";
|
|
3
|
+
import Signal from "../../../../../core/events/signal/Signal.js";
|
|
4
|
+
import { AssetManager } from "../../../../asset/AssetManager.js";
|
|
5
|
+
import { GameAssetType } from "../../../../asset/GameAssetType.js";
|
|
6
|
+
import { compose_finger_print } from "./tile/compose_finger_print.js";
|
|
7
|
+
import { decompose_finger_print } from "./tile/decompose_finger_print.js";
|
|
8
|
+
import { TextureTile } from "./tile/TextureTile.js";
|
|
9
|
+
|
|
10
|
+
export class TileLoader {
|
|
11
|
+
/**
|
|
12
|
+
* Where the tiles are stored
|
|
13
|
+
* @type {string}
|
|
14
|
+
*/
|
|
15
|
+
#root_path = "";
|
|
16
|
+
|
|
17
|
+
set path(v) {
|
|
18
|
+
this.#root_path = v;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* When queue gets larger than this, we start discarding elements
|
|
23
|
+
* @type {number}
|
|
24
|
+
*/
|
|
25
|
+
queue_limit = Infinity;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @type {AssetManager}
|
|
30
|
+
*/
|
|
31
|
+
#asset_manager = null;
|
|
32
|
+
|
|
33
|
+
set asset_manager(v) {
|
|
34
|
+
this.#asset_manager = v;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* How many tiles can be loaded at the same time
|
|
39
|
+
* @type {number}
|
|
40
|
+
*/
|
|
41
|
+
#concurrency = 2;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Tiles that are currently being loaded
|
|
45
|
+
* @readonly
|
|
46
|
+
* @type {number[]}
|
|
47
|
+
*/
|
|
48
|
+
#in_flight = [];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Contains fingerprints
|
|
52
|
+
* @readonly
|
|
53
|
+
* @type {number[]}
|
|
54
|
+
*/
|
|
55
|
+
#queue = [];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @readonly
|
|
59
|
+
*/
|
|
60
|
+
on = {
|
|
61
|
+
/**
|
|
62
|
+
* @type {Signal<TextureTile>}
|
|
63
|
+
*/
|
|
64
|
+
loaded: new Signal()
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
* @param {number} fingerprint
|
|
71
|
+
* @returns {boolean}
|
|
72
|
+
*/
|
|
73
|
+
#queue_remove(fingerprint) {
|
|
74
|
+
assert.isNonNegativeInteger(fingerprint, 'fingerprint');
|
|
75
|
+
|
|
76
|
+
const i = this.#queue.indexOf(fingerprint);
|
|
77
|
+
|
|
78
|
+
if (i === -1) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.#queue.splice(i, 1);
|
|
83
|
+
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#queue_add(fingerprint) {
|
|
88
|
+
assert.isNonNegativeInteger(fingerprint, 'fingerprint');
|
|
89
|
+
|
|
90
|
+
if (this.is_queued(fingerprint)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
this.#queue.push(fingerprint);
|
|
95
|
+
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
*
|
|
101
|
+
* @param {number} fingerprint
|
|
102
|
+
*/
|
|
103
|
+
enqueue(fingerprint) {
|
|
104
|
+
if (this.#in_flight.indexOf(fingerprint) !== -1) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (this.#queue_add(fingerprint) === false) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.#prod();
|
|
113
|
+
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
*
|
|
119
|
+
* @param {number} fingerprint
|
|
120
|
+
* @returns {boolean}
|
|
121
|
+
*/
|
|
122
|
+
is_queued(fingerprint) {
|
|
123
|
+
assert.isNonNegativeInteger(fingerprint, 'fingerprint');
|
|
124
|
+
|
|
125
|
+
return this.#queue.indexOf(fingerprint) !== -1;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
*
|
|
130
|
+
* @param {UsageMetadata} usage
|
|
131
|
+
*/
|
|
132
|
+
#sort_queue_by_usage(usage) {
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
*
|
|
136
|
+
* @param {number} fingerprint
|
|
137
|
+
*/
|
|
138
|
+
const score = (fingerprint) => -usage.getCountByFingerprint(fingerprint);
|
|
139
|
+
|
|
140
|
+
arrayQuickSort(
|
|
141
|
+
this.#queue,
|
|
142
|
+
score, null,
|
|
143
|
+
0, this.#queue.length - 1
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
*
|
|
150
|
+
* @param {UsageMetadata} usage
|
|
151
|
+
*/
|
|
152
|
+
update_usage(usage) {
|
|
153
|
+
this.#sort_queue_by_usage(usage);
|
|
154
|
+
|
|
155
|
+
// truncate the queue if necessary
|
|
156
|
+
const queue_overflow = this.#queue.length - this.queue_limit;
|
|
157
|
+
if (queue_overflow > 0) {
|
|
158
|
+
this.#queue.splice(this.queue_limit, queue_overflow);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
*
|
|
164
|
+
* @param {number} mip
|
|
165
|
+
* @param {number} x
|
|
166
|
+
* @param {number} y
|
|
167
|
+
* @returns {string}
|
|
168
|
+
*/
|
|
169
|
+
#build_file_name(mip, x, y) {
|
|
170
|
+
|
|
171
|
+
assert.isNonNegativeInteger(mip, 'mip');
|
|
172
|
+
assert.isNonNegativeInteger(x, 'x');
|
|
173
|
+
assert.isNonNegativeInteger(y, 'y');
|
|
174
|
+
|
|
175
|
+
return `${mip}-${x}-${y}.png`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Initializes load of the next element in the queue if there is capacity
|
|
180
|
+
*/
|
|
181
|
+
#prod() {
|
|
182
|
+
while (this.#in_flight.length < this.#concurrency && this.#queue.length > 0) {
|
|
183
|
+
const fingerprint = this.#queue[0];
|
|
184
|
+
const { mip, x, y } = decompose_finger_print(fingerprint);
|
|
185
|
+
|
|
186
|
+
this.#load(mip, x, y);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
*
|
|
192
|
+
* @param {number} mip
|
|
193
|
+
* @param {number} x
|
|
194
|
+
* @param {number} y
|
|
195
|
+
* @returns {Promise<TextureTile>}
|
|
196
|
+
*/
|
|
197
|
+
#load(mip, x, y) {
|
|
198
|
+
const file_name = this.#build_file_name(mip, x, y);
|
|
199
|
+
const finger_print = compose_finger_print(mip, x, y);
|
|
200
|
+
|
|
201
|
+
this.#queue_remove(finger_print);
|
|
202
|
+
this.#in_flight.push(finger_print);
|
|
203
|
+
|
|
204
|
+
return this.#asset_manager.promise(`${this.#root_path}/${file_name}`, GameAssetType.Image)
|
|
205
|
+
.then(asset => {
|
|
206
|
+
|
|
207
|
+
const sampler = asset.create();
|
|
208
|
+
|
|
209
|
+
const tile = new TextureTile();
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
tile.data = sampler;
|
|
213
|
+
tile.finder_print = finger_print;
|
|
214
|
+
|
|
215
|
+
this.on.loaded.send1(tile);
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
return tile;
|
|
219
|
+
}, (reason) => {
|
|
220
|
+
console.error(`Failed to load tile ${file_name}, reason:${reason}`);
|
|
221
|
+
})
|
|
222
|
+
.finally(() => {
|
|
223
|
+
|
|
224
|
+
const index = this.#in_flight.indexOf(finger_print);
|
|
225
|
+
this.#in_flight.splice(index, 1);
|
|
226
|
+
|
|
227
|
+
this.#prod();
|
|
228
|
+
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -1,182 +1,166 @@
|
|
|
1
|
-
import { array_get_index_in_range } from "../../../../../core/collection/array/array_get_index_in_range.js";
|
|
2
|
-
import { array_swap } from "../../../../../core/collection/array/array_swap.js";
|
|
3
1
|
import { arrayQuickSort } from "../../../../../core/collection/array/arrayQuickSort.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { compose_finger_print } from "./tile/compose_finger_print.js";
|
|
3
|
+
import { finger_print_to_tile_address } from "./tile/finger_print_to_tile_address.js";
|
|
6
4
|
|
|
7
|
-
const DEFAULT_CAPACITY = 64;
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* @param {number} finger_print
|
|
12
|
-
* @returns {number}
|
|
13
|
-
*/
|
|
14
|
-
function finger_print_to_tile_index(finger_print) {
|
|
15
|
-
// decode fingerprint
|
|
16
|
-
const mip = (finger_print >> 24) & 0xFF;
|
|
17
|
-
const x = (finger_print >> 16) & 0xFF;
|
|
18
|
-
const y = (finger_print >> 8) & 0xFF;
|
|
6
|
+
function compose_tile_address(mip, x, y) {
|
|
7
|
+
const finger_print = compose_finger_print(mip, x, y);
|
|
19
8
|
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
return finger_print_to_tile_address(finger_print);
|
|
10
|
+
}
|
|
22
11
|
|
|
23
|
-
|
|
24
|
-
const mip_mask = mip_resolution - 1;
|
|
12
|
+
export class UsageMetadata {
|
|
25
13
|
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
#counts_intrinsic = new Uint32Array(0);
|
|
15
|
+
/**
|
|
16
|
+
* Stores indices of tiles with usage > 0
|
|
17
|
+
* @type {Uint32Array}
|
|
18
|
+
*/
|
|
19
|
+
#occupancy = new Uint32Array(0);
|
|
20
|
+
/**
|
|
21
|
+
* Points at the end of the occupancy list
|
|
22
|
+
* @type {number}
|
|
23
|
+
*/
|
|
24
|
+
#occupancy_cursor = 0;
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
get counts() {
|
|
27
|
+
return this.#counts_intrinsic;
|
|
28
|
+
}
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
#max_mip_level = 0;
|
|
33
31
|
|
|
34
|
-
#cursor = 0;
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
set max_mip_level(v) {
|
|
34
|
+
this.#max_mip_level = v;
|
|
38
35
|
|
|
39
|
-
|
|
36
|
+
this.#ensureCapacity();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get max_mip_level() {
|
|
40
|
+
return this.#max_mip_level;
|
|
41
|
+
}
|
|
40
42
|
|
|
41
|
-
#capacity = 0;
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
this.#
|
|
44
|
+
get occupancy() {
|
|
45
|
+
return this.#occupancy;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get occupancy_count() {
|
|
49
|
+
return this.#occupancy_cursor;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
/**
|
|
48
53
|
*
|
|
49
|
-
* @param {number} min_size
|
|
50
54
|
*/
|
|
51
|
-
#ensureCapacity(
|
|
52
|
-
if (this.#capacity >= min_size) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const buffer = new ArrayBuffer(min_size * 2 * 4);
|
|
55
|
+
#ensureCapacity() {
|
|
57
56
|
|
|
58
|
-
this.#
|
|
59
|
-
this.#counts = new Uint32Array(buffer, min_size * 4, min_size);
|
|
57
|
+
const size = compose_tile_address(this.#max_mip_level + 1, 0, 0);
|
|
60
58
|
|
|
61
|
-
this.#
|
|
62
|
-
|
|
59
|
+
if (this.#counts_intrinsic.length >= size) {
|
|
60
|
+
// already large enough
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
this.#counts_intrinsic = new Uint32Array(size);
|
|
65
|
+
this.#occupancy = new Uint32Array(size);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
* @param {number} fingerprint
|
|
71
|
+
* @returns {number}
|
|
72
|
+
*/
|
|
73
|
+
getCountByFingerprint(fingerprint) {
|
|
74
|
+
const index = finger_print_to_tile_address(fingerprint);
|
|
71
75
|
|
|
72
|
-
|
|
73
|
-
return this.#counts[index];
|
|
76
|
+
return this.#counts_intrinsic[index];
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
/**
|
|
80
|
+
*
|
|
81
|
+
* @param {number} mip
|
|
82
|
+
* @param {number} x
|
|
83
|
+
* @param {number} y
|
|
84
|
+
* @returns {number}
|
|
85
|
+
*/
|
|
86
|
+
getCountBy(mip, x, y) {
|
|
87
|
+
const address = compose_tile_address(mip, x, y);
|
|
80
88
|
|
|
81
|
-
|
|
82
|
-
array_swap(
|
|
83
|
-
this.#lookup,
|
|
84
|
-
a,
|
|
85
|
-
this.#lookup,
|
|
86
|
-
b,
|
|
87
|
-
1
|
|
88
|
-
);
|
|
89
|
-
array_swap(
|
|
90
|
-
this.#counts,
|
|
91
|
-
a,
|
|
92
|
-
this.#counts,
|
|
93
|
-
b,
|
|
94
|
-
1
|
|
95
|
-
);
|
|
89
|
+
return this.#counts_intrinsic[address];
|
|
96
90
|
}
|
|
97
91
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
});
|
|
92
|
+
clear() {
|
|
93
|
+
this.#counts_intrinsic.fill(0);
|
|
94
|
+
this.#occupancy_cursor = 0;
|
|
102
95
|
}
|
|
103
96
|
|
|
104
97
|
/**
|
|
105
98
|
* Given existing usage, award same usage to all tiles up the chain all the way to the root
|
|
106
99
|
* This helps avoid popping and ensures that when there's not enough space - at least the higher level LOD tiles are available
|
|
107
100
|
* @param {number} bias added to the ancestor tiles to make them more likely to be loaded
|
|
108
|
-
* @returns {number} number of tiles added
|
|
109
101
|
*/
|
|
110
|
-
promoteAncestors(bias =
|
|
111
|
-
const start_cursor = this.#cursor;
|
|
102
|
+
promoteAncestors(bias = 1) {
|
|
112
103
|
|
|
113
|
-
|
|
114
|
-
|
|
104
|
+
// traverse mip pyramid in reverse, so we can push counts to parents one level at a time
|
|
105
|
+
for (let mip = this.#max_mip_level; mip > 0; mip--) {
|
|
115
106
|
|
|
116
|
-
|
|
107
|
+
const mip_resolution = 1 << mip;
|
|
117
108
|
|
|
118
|
-
let
|
|
109
|
+
for (let y = 0; y < mip_resolution; y++) {
|
|
110
|
+
for (let x = 0; x < mip_resolution; x++) {
|
|
119
111
|
|
|
120
|
-
|
|
112
|
+
const count = this.getCountBy(mip, x, y);
|
|
121
113
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
114
|
+
if (count <= 0) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
125
117
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
118
|
+
// get higher-level lod
|
|
119
|
+
const parent_level = mip - 1;
|
|
120
|
+
const parent_x = x >>> 1;
|
|
121
|
+
const parent_y = y >>> 1;
|
|
130
122
|
|
|
131
|
-
|
|
132
|
-
(parent_level << 24)
|
|
133
|
-
| (parent_x << 16)
|
|
134
|
-
| (parent_y << 8)
|
|
135
|
-
| (texture_id << 0);
|
|
123
|
+
const parent_index = compose_tile_address(parent_level, parent_x, parent_y);
|
|
136
124
|
|
|
137
|
-
|
|
125
|
+
const parent_count = this.#counts_intrinsic[parent_index];
|
|
138
126
|
|
|
139
|
-
|
|
140
|
-
const parent_count = this.#counts[parent_index];
|
|
127
|
+
const expected_count = count + bias;
|
|
141
128
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
this.#counts[parent_index] = push_value;
|
|
129
|
+
if (parent_count < expected_count) {
|
|
130
|
+
this.#counts_intrinsic[parent_index] = expected_count;
|
|
148
131
|
|
|
132
|
+
if (parent_count === 0) {
|
|
133
|
+
this.#append_to_occupancy(parent_index);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
149
136
|
|
|
150
|
-
|
|
151
|
-
finger_print = parent_finger_print;
|
|
152
|
-
level = parent_level;
|
|
153
|
-
|
|
154
|
-
index = parent_index;
|
|
137
|
+
}
|
|
155
138
|
}
|
|
156
|
-
}
|
|
157
139
|
|
|
158
|
-
|
|
140
|
+
}
|
|
159
141
|
}
|
|
160
142
|
|
|
161
143
|
/**
|
|
162
144
|
*
|
|
163
|
-
* @param {number}
|
|
164
|
-
* @returns {number}
|
|
145
|
+
* @param {number} address
|
|
165
146
|
*/
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
let index = array_get_index_in_range(lookup, finger_print, 0, this.#cursor - 1);
|
|
171
|
-
|
|
172
|
-
if (index === -1) {
|
|
173
|
-
index = this.#cursor++;
|
|
174
|
-
lookup[index] = finger_print;
|
|
175
|
-
}
|
|
147
|
+
#append_to_occupancy(address) {
|
|
148
|
+
this.#occupancy[this.#occupancy_cursor] = address;
|
|
149
|
+
this.#occupancy_cursor++;
|
|
150
|
+
}
|
|
176
151
|
|
|
177
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Sort occupancy list in descending order
|
|
154
|
+
*/
|
|
155
|
+
sortOccupancy() {
|
|
156
|
+
arrayQuickSort(
|
|
157
|
+
this.#occupancy,
|
|
158
|
+
(index) => -this.#counts_intrinsic[index], null,
|
|
159
|
+
0, this.#occupancy_cursor - 1
|
|
160
|
+
);
|
|
178
161
|
}
|
|
179
162
|
|
|
163
|
+
|
|
180
164
|
/**
|
|
181
165
|
*
|
|
182
166
|
* @param {Uint8Array} data usage texture data
|
|
@@ -186,12 +170,17 @@ export class UsageMetadata {
|
|
|
186
170
|
|
|
187
171
|
const data_size = data.length;
|
|
188
172
|
|
|
189
|
-
this.#ensureCapacity(
|
|
173
|
+
this.#ensureCapacity();
|
|
190
174
|
|
|
191
|
-
const counts = this.#
|
|
175
|
+
const counts = this.#counts_intrinsic;
|
|
192
176
|
|
|
193
177
|
for (let offset = 0; offset < data_size; offset += 4) {
|
|
194
178
|
|
|
179
|
+
if (data[offset + 3] === 0) {
|
|
180
|
+
// no data
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
195
184
|
const mip_level = data[offset];
|
|
196
185
|
|
|
197
186
|
// we create a mask to make sure we don't end up with invalid tile position values
|
|
@@ -200,21 +189,16 @@ export class UsageMetadata {
|
|
|
200
189
|
const tile_x = data[offset + 1] & max_tile_value;
|
|
201
190
|
const tile_y = data[offset + 2] & max_tile_value;
|
|
202
191
|
|
|
203
|
-
const
|
|
192
|
+
const tile_address = compose_tile_address(mip_level, tile_x, tile_y);
|
|
204
193
|
|
|
205
|
-
const
|
|
206
|
-
(mip_level << 24)
|
|
207
|
-
| (tile_x << 16)
|
|
208
|
-
| (tile_y << 8)
|
|
209
|
-
| (texture_id << 0);
|
|
194
|
+
const previous_count = counts[tile_address];
|
|
210
195
|
|
|
211
|
-
if (
|
|
212
|
-
|
|
196
|
+
if (previous_count === 0) {
|
|
197
|
+
// first occurrence, mark occupancy
|
|
198
|
+
this.#append_to_occupancy(tile_address);
|
|
213
199
|
}
|
|
214
200
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
counts[index]++;
|
|
201
|
+
counts[tile_address] = previous_count + 1;
|
|
218
202
|
}
|
|
219
203
|
|
|
220
204
|
}
|