@needle-tools/gltf-progressive 3.6.0-alpha.2 → 3.6.0-alpha.3

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/lib/extension.js CHANGED
@@ -223,13 +223,19 @@ export class NEEDLE_progressive {
223
223
  }
224
224
  // const info = this.onProgressiveLoadStart(context, source, mesh, null);
225
225
  mesh["LOD:requested level"] = level;
226
- return NEEDLE_progressive.getOrLoadLOD(currentGeometry, level).then(geo => {
226
+ const shouldLoad = () => mesh["LOD:requested level"] === level || this.shouldApplyStaleMeshLOD(mesh, level);
227
+ return NEEDLE_progressive.getOrLoadLOD(currentGeometry, level, {
228
+ isCurrent: shouldLoad,
229
+ }).then(geo => {
227
230
  if (Array.isArray(geo)) {
228
231
  const index = lodinfo.index || 0;
229
232
  geo = geo[index];
230
233
  }
231
- if (mesh["LOD:requested level"] === level) {
232
- delete mesh["LOD:requested level"];
234
+ const isLatestRequest = mesh["LOD:requested level"] === level;
235
+ if (isLatestRequest || this.shouldApplyStaleMeshLOD(mesh, level)) {
236
+ if (isLatestRequest) {
237
+ delete mesh["LOD:requested level"];
238
+ }
233
239
  if (geo && currentGeometry != geo) {
234
240
  const isGeometry = geo?.isBufferGeometry;
235
241
  // if (debug == "verbose") console.log("Progressive Mesh " + mesh.name + " loaded", currentGeometry, "→", geo, "\n", mesh)
@@ -373,7 +379,14 @@ export class NEEDLE_progressive {
373
379
  return pending.promise;
374
380
  }
375
381
  }
376
- const promise = NEEDLE_progressive.getOrLoadLOD(current, level).then(tex => {
382
+ const requestId = material && slot ? this.nextTextureSlotRequestId(material, slot, level, force) : 0;
383
+ const isCurrentRequest = () => !material || !slot || this.getLatestTextureSlotRequest(material, slot)?.id === requestId;
384
+ const shouldLoad = () => isCurrentRequest() || this.shouldApplyStaleTextureSlotLOD(material, slot, level, force);
385
+ const promise = NEEDLE_progressive.getOrLoadLOD(current, level, {
386
+ isCurrent: shouldLoad,
387
+ }).then(tex => {
388
+ if (!isCurrentRequest() && !this.shouldApplyStaleTextureSlotLOD(material, slot, level, force))
389
+ return null;
377
390
  // this can currently not happen
378
391
  if (Array.isArray(tex)) {
379
392
  console.warn("Progressive: Got an array of textures for a texture slot, this should not happen...");
@@ -415,7 +428,7 @@ export class NEEDLE_progressive {
415
428
  return null;
416
429
  });
417
430
  if (material && slot) {
418
- this.setPendingTextureSlotRequest(material, slot, level, force, promise);
431
+ this.setPendingTextureSlotRequest(material, slot, level, force, requestId, promise);
419
432
  }
420
433
  return promise;
421
434
  }
@@ -423,6 +436,8 @@ export class NEEDLE_progressive {
423
436
  // referenced by many slots and should only be disposed after every slot moved away.
424
437
  static trackedTextureSlots = new WeakMap();
425
438
  static pendingTextureSlotRequests = new WeakMap();
439
+ static latestTextureSlotRequests = new WeakMap();
440
+ static textureSlotRequestId = 0;
426
441
  static trackCurrentMaterialTextureSlots(material) {
427
442
  if (material.uniforms && (material.isRawShaderMaterial || material.isShaderMaterial === true)) {
428
443
  const shaderMaterial = material;
@@ -444,17 +459,52 @@ export class NEEDLE_progressive {
444
459
  static getPendingTextureSlotRequest(material, slot) {
445
460
  return this.pendingTextureSlotRequests.get(material)?.get(slot);
446
461
  }
447
- static setPendingTextureSlotRequest(material, slot, level, force, promise) {
462
+ static nextTextureSlotRequestId(material, slot, level, force) {
463
+ let slots = this.latestTextureSlotRequests.get(material);
464
+ if (!slots) {
465
+ slots = new Map();
466
+ this.latestTextureSlotRequests.set(material, slots);
467
+ }
468
+ const id = ++this.textureSlotRequestId;
469
+ slots.set(slot, { id, level, force });
470
+ return id;
471
+ }
472
+ static getLatestTextureSlotRequest(material, slot) {
473
+ return this.latestTextureSlotRequests.get(material)?.get(slot);
474
+ }
475
+ static shouldApplyStaleTextureSlotLOD(material, slot, level, force) {
476
+ if (!material || !slot)
477
+ return false;
478
+ const latest = this.getLatestTextureSlotRequest(material, slot);
479
+ const assigned = this.getMaterialTextureSlot(material, slot);
480
+ const assignedLODLevel = this.getAssignedLODInformation(assigned)?.level ?? Infinity;
481
+ if (level >= assignedLODLevel)
482
+ return false;
483
+ if (force) {
484
+ if (!latest)
485
+ return false;
486
+ return level >= latest.level;
487
+ }
488
+ return true;
489
+ }
490
+ static shouldApplyStaleMeshLOD(mesh, level) {
491
+ const latestLevel = mesh["LOD:requested level"];
492
+ if (typeof latestLevel !== "number")
493
+ return false;
494
+ const assignedLODLevel = this.getAssignedLODInformation(mesh.geometry)?.level ?? Infinity;
495
+ return level < assignedLODLevel && level >= latestLevel;
496
+ }
497
+ static setPendingTextureSlotRequest(material, slot, level, force, id, promise) {
448
498
  let slots = this.pendingTextureSlotRequests.get(material);
449
499
  if (!slots) {
450
500
  slots = new Map();
451
501
  this.pendingTextureSlotRequests.set(material, slots);
452
502
  }
453
- const request = { level, force, promise };
503
+ const request = { level, force, id, promise };
454
504
  slots.set(slot, request);
455
505
  promise.finally(() => {
456
506
  const current = slots.get(slot);
457
- if (current === request) {
507
+ if (current?.id === id) {
458
508
  slots.delete(slot);
459
509
  }
460
510
  });
@@ -771,6 +821,8 @@ export class NEEDLE_progressive {
771
821
  this.textureRefCounts.clear();
772
822
  this.trackedTextureSlots = new WeakMap();
773
823
  this.pendingTextureSlotRequests = new WeakMap();
824
+ this.latestTextureSlotRequests = new WeakMap();
825
+ this.textureSlotRequestId = 0;
774
826
  }
775
827
  }
776
828
  /** Dispose a single cache entry's three.js resource(s) to free GPU memory. */
@@ -889,7 +941,7 @@ export class NEEDLE_progressive {
889
941
  }
890
942
  static workers = [];
891
943
  static _workersIndex = 0;
892
- static async getOrLoadLOD(current, level) {
944
+ static async getOrLoadLOD(current, level, options) {
893
945
  const debugverbose = debug == "verbose";
894
946
  /** this key is used to lookup the LOD information */
895
947
  const LOD = this.getAssignedLODInformation(current);
@@ -962,7 +1014,17 @@ export class NEEDLE_progressive {
962
1014
  const cached = await this.tryResolveLODCacheEntry(this.cache.get(KEY), KEY, lod_url, current, level, debugverbose);
963
1015
  if (cached.found)
964
1016
  return cached.value;
1017
+ if (options?.isCurrent?.() === false) {
1018
+ if (debugverbose)
1019
+ console.log(`Skipping stale LOD ${level} request before queue: ${lod_url}`);
1020
+ return null;
1021
+ }
965
1022
  const slot = await this.queue.slot(lod_url);
1023
+ if (options?.isCurrent?.() === false) {
1024
+ if (debugverbose)
1025
+ console.log(`Skipping stale LOD ${level} request after queue: ${lod_url}`);
1026
+ return null;
1027
+ }
966
1028
  // Another request can fill the cache while this one waits for a queue slot.
967
1029
  // Re-checking here avoids duplicate loads for heavily instanced assets.
968
1030
  const cachedAfterQueue = await this.tryResolveLODCacheEntry(this.cache.get(KEY), KEY, lod_url, current, level, debugverbose);
@@ -1143,10 +1205,19 @@ export class NEEDLE_progressive {
1143
1205
  }
1144
1206
  else {
1145
1207
  if (current instanceof Texture) {
1208
+ if (options?.isCurrent?.() === false) {
1209
+ if (debugverbose)
1210
+ console.log(`Skipping stale texture LOD ${level} request: ${lod_url}`);
1211
+ return null;
1212
+ }
1146
1213
  if (debugverbose)
1147
1214
  console.log("Load texture from uri: " + lod_url);
1148
1215
  const loader = new TextureLoader();
1149
1216
  const tex = await loader.loadAsync(lod_url);
1217
+ if (options?.isCurrent?.() === false) {
1218
+ tex?.dispose();
1219
+ return null;
1220
+ }
1150
1221
  if (tex) {
1151
1222
  tex.guid = lodInfo.guid;
1152
1223
  tex.flipY = false;
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // replaced at build time
2
- export const version = "3.6.0-alpha.2";
2
+ export const version = "3.6.0-alpha.3";
3
3
  globalThis["GLTF_PROGRESSIVE_VERSION"] = version;
4
4
  console.debug(`[gltf-progressive] version ${version || "-"}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-progressive",
3
- "version": "3.6.0-alpha.2",
3
+ "version": "3.6.0-alpha.3",
4
4
  "description": "three.js support for loading glTF or GLB files that contain progressive loading data",
5
5
  "homepage": "https://needle.tools",
6
6
  "author": {