45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
import * as THREE from "three";
|
|
|
|
// Each viewer owns its textures. Browser HTTP caching handles repeat downloads;
|
|
// keeping GPU resources in a global cache leaks every visited map and signed URL.
|
|
export async function loadPanoramaTextures(
|
|
urls: string[],
|
|
loader: Pick<THREE.TextureLoader, "loadAsync"> = new THREE.TextureLoader(),
|
|
timeoutMs = 30000,
|
|
): Promise<THREE.Texture[]> {
|
|
const textures: THREE.Texture[] = [];
|
|
let failed = false;
|
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
try {
|
|
return await Promise.race([
|
|
Promise.all(
|
|
urls.map(async (url) => {
|
|
const texture = await loader.loadAsync(url);
|
|
if (failed) {
|
|
texture.dispose();
|
|
throw new Error("Panorama loading cancelled");
|
|
}
|
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
textures.push(texture);
|
|
return texture;
|
|
}),
|
|
),
|
|
new Promise<never>((_, reject) => {
|
|
timer = setTimeout(
|
|
() =>
|
|
reject(
|
|
new Error("Panorama loading timed out. Reconnect to retry."),
|
|
),
|
|
timeoutMs,
|
|
);
|
|
}),
|
|
]);
|
|
} catch (error) {
|
|
failed = true;
|
|
textures.forEach((texture) => texture.dispose());
|
|
throw error;
|
|
} finally {
|
|
clearTimeout(timer);
|
|
}
|
|
}
|