@cesium/engine
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
825 lines (724 loc) • 27.1 kB
JavaScript
import Check from "../Core/Check.js";
import Frozen from "../Core/Frozen.js";
import defined from "../Core/defined.js";
import DeveloperError from "../Core/DeveloperError.js";
import BufferLoader from "./BufferLoader.js";
import GltfBufferViewLoader from "./GltfBufferViewLoader.js";
import GltfDracoLoader from "./GltfDracoLoader.js";
import GltfImageLoader from "./GltfImageLoader.js";
import GltfIndexBufferLoader from "./GltfIndexBufferLoader.js";
import GltfJsonLoader from "./GltfJsonLoader.js";
import GltfTextureLoader from "./GltfTextureLoader.js";
import GltfVertexBufferLoader from "./GltfVertexBufferLoader.js";
import GltfSpzLoader from "./GltfSpzLoader.js";
import MetadataSchemaLoader from "./MetadataSchemaLoader.js";
import ResourceCacheKey from "./ResourceCacheKey.js";
import ResourceCacheStatistics from "./ResourceCacheStatistics.js";
/**
* Cache for resources shared across 3D Tiles and glTF.
*
* @namespace ResourceCache
*
* @private
*/
function ResourceCache() {}
ResourceCache.cacheEntries = {};
// Statistics about binary data stored in the resource cache
ResourceCache.statistics = new ResourceCacheStatistics();
/**
* A reference-counted cache entry.
*
* @param {ResourceLoader} resourceLoader The resource.
*
* @alias CacheEntry
* @constructor
*
* @private
*/
function CacheEntry(resourceLoader) {
this.referenceCount = 1;
this.resourceLoader = resourceLoader;
// For unit testing only
this._statisticsPromise = undefined;
}
/**
* Gets a resource from the cache. If the resource exists its reference count is
* incremented. Otherwise, if no resource loader exists, undefined is returned.
*
* @param {string} cacheKey The cache key of the resource.
*
* @returns {ResourceLoader|undefined} The resource.
* @private
*/
ResourceCache.get = function (cacheKey) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.string("cacheKey", cacheKey);
//>>includeEnd('debug');
const cacheEntry = ResourceCache.cacheEntries[cacheKey];
if (defined(cacheEntry)) {
++cacheEntry.referenceCount;
return cacheEntry.resourceLoader;
}
return undefined;
};
/**
* Adds it to the cache.
*
* @param {ResourceLoader} resourceLoader The resource.
* @returns {ResourceLoader} The resource.
*
* @exception {DeveloperError} Resource with this cacheKey is already in the cache
* @private
*/
ResourceCache.add = function (resourceLoader) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("resourceLoader", resourceLoader);
//>>includeEnd('debug');
const cacheKey = resourceLoader.cacheKey;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.string("options.resourceLoader.cacheKey", cacheKey);
if (defined(ResourceCache.cacheEntries[cacheKey])) {
throw new DeveloperError(
`Resource with this cacheKey is already in the cache: ${cacheKey}`,
);
}
//>>includeEnd('debug');
ResourceCache.cacheEntries[cacheKey] = new CacheEntry(resourceLoader);
return resourceLoader;
};
/**
* Unloads a resource from the cache. When the reference count hits zero the
* resource is destroyed.
*
* @param {ResourceLoader} resourceLoader The resource.
*
* @exception {DeveloperError} Resource is not in the cache.
* @exception {DeveloperError} Cannot unload resource that has no references.
* @private
*/
ResourceCache.unload = function (resourceLoader) {
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("resourceLoader", resourceLoader);
//>>includeEnd('debug');
const cacheKey = resourceLoader.cacheKey;
const cacheEntry = ResourceCache.cacheEntries[cacheKey];
//>>includeStart('debug', pragmas.debug);
if (!defined(cacheEntry)) {
throw new DeveloperError(`Resource is not in the cache: ${cacheKey}`);
}
//>>includeEnd('debug');
--cacheEntry.referenceCount;
if (cacheEntry.referenceCount === 0) {
ResourceCache.statistics.removeLoader(resourceLoader);
resourceLoader.destroy();
delete ResourceCache.cacheEntries[cacheKey];
}
};
/**
* Gets an existing schema loader from the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {object} [options.schema] An object that explicitly defines a schema JSON. Mutually exclusive with options.resource.
* @param {Resource} [options.resource] The {@link Resource} pointing to the schema JSON. Mutually exclusive with options.schema.
*
* @returns {MetadataSchemaLoader} The cached schema resource.
*
* @exception {DeveloperError} One of options.schema and options.resource must be defined.
* @private
*/
ResourceCache.getSchemaLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const { schema, resource } = options;
//>>includeStart('debug', pragmas.debug);
if (defined(schema) === defined(resource)) {
throw new DeveloperError(
"One of options.schema and options.resource must be defined.",
);
}
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getSchemaCacheKey({
schema: schema,
resource: resource,
});
let schemaLoader = ResourceCache.get(cacheKey);
if (defined(schemaLoader)) {
return schemaLoader;
}
schemaLoader = new MetadataSchemaLoader({
schema: schema,
resource: resource,
cacheKey: cacheKey,
});
return ResourceCache.add(schemaLoader);
};
/**
* Gets an existing embedded buffer loader from the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {Resource} options.parentResource The {@link Resource} containing the embedded buffer.
* @param {number} options.bufferId A unique identifier of the embedded buffer within the parent resource.
* @param {Uint8Array} [options.typedArray] The typed array containing the embedded buffer contents.
*
* @returns {BufferLoader} The cached buffer loader.
* @private
*/
ResourceCache.getEmbeddedBufferLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const { parentResource, bufferId, typedArray } = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.parentResource", parentResource);
Check.typeOf.number("options.bufferId", bufferId);
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getEmbeddedBufferCacheKey({
parentResource: parentResource,
bufferId: bufferId,
});
let bufferLoader = ResourceCache.get(cacheKey);
if (defined(bufferLoader)) {
return bufferLoader;
}
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.typedArray", typedArray);
//>>includeEnd('debug');
bufferLoader = new BufferLoader({
typedArray: typedArray,
cacheKey: cacheKey,
});
return ResourceCache.add(bufferLoader);
};
/**
* Gets an existing external buffer from loader the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {Resource} options.resource The {@link Resource} pointing to the external buffer.
*
* @returns {BufferLoader} The cached buffer loader.
* @private
*/
ResourceCache.getExternalBufferLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const { resource } = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.resource", resource);
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getExternalBufferCacheKey({
resource: resource,
});
let bufferLoader = ResourceCache.get(cacheKey);
if (defined(bufferLoader)) {
return bufferLoader;
}
bufferLoader = new BufferLoader({
resource: resource,
cacheKey: cacheKey,
});
return ResourceCache.add(bufferLoader);
};
/**
* Gets an existing glTF JSON loader from the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
* @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
* @param {Uint8Array} [options.typedArray] The typed array containing the glTF contents.
* @param {object} [options.gltfJson] The parsed glTF JSON contents.
*
* @returns {GltfJsonLoader} The cached glTF JSON loader.
* @private
*/
ResourceCache.getGltfJsonLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const { gltfResource, baseResource, typedArray, gltfJson } = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.gltfResource", gltfResource);
Check.typeOf.object("options.baseResource", baseResource);
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getGltfCacheKey({
gltfResource: gltfResource,
});
let gltfJsonLoader = ResourceCache.get(cacheKey);
if (defined(gltfJsonLoader)) {
return gltfJsonLoader;
}
gltfJsonLoader = new GltfJsonLoader({
resourceCache: ResourceCache,
gltfResource: gltfResource,
baseResource: baseResource,
typedArray: typedArray,
gltfJson: gltfJson,
cacheKey: cacheKey,
});
return ResourceCache.add(gltfJsonLoader);
};
/**
* Gets an existing glTF buffer view from the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {object} options.gltf The glTF JSON.
* @param {number} options.bufferViewId The bufferView ID.
* @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
* @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
*
* @returns {GltfBufferViewLoader} The cached buffer view loader.
* @private
*/
ResourceCache.getBufferViewLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const { gltf, bufferViewId, gltfResource, baseResource } = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.gltf", gltf);
Check.typeOf.number("options.bufferViewId", bufferViewId);
Check.typeOf.object("options.gltfResource", gltfResource);
Check.typeOf.object("options.baseResource", baseResource);
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getBufferViewCacheKey({
gltf: gltf,
bufferViewId: bufferViewId,
gltfResource: gltfResource,
baseResource: baseResource,
});
let bufferViewLoader = ResourceCache.get(cacheKey);
if (defined(bufferViewLoader)) {
return bufferViewLoader;
}
bufferViewLoader = new GltfBufferViewLoader({
resourceCache: ResourceCache,
gltf: gltf,
bufferViewId: bufferViewId,
gltfResource: gltfResource,
baseResource: baseResource,
cacheKey: cacheKey,
});
return ResourceCache.add(bufferViewLoader);
};
/**
* Gets an existing Draco data from the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {object} options.gltf The glTF JSON.
* @param {object} options.primitive The primitive containing the Draco extension.
* @param {object} options.draco The Draco extension object.
* @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
* @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
*
* @returns {GltfDracoLoader} The cached Draco loader.
* @private
*/
ResourceCache.getDracoLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const { gltf, primitive, draco, gltfResource, baseResource } = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.gltf", gltf);
Check.typeOf.object("options.primitive", primitive);
Check.typeOf.object("options.draco", draco);
Check.typeOf.object("options.gltfResource", gltfResource);
Check.typeOf.object("options.baseResource", baseResource);
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getDracoCacheKey({
gltf: gltf,
draco: draco,
gltfResource: gltfResource,
baseResource: baseResource,
});
let dracoLoader = ResourceCache.get(cacheKey);
if (defined(dracoLoader)) {
return dracoLoader;
}
dracoLoader = new GltfDracoLoader({
resourceCache: ResourceCache,
gltf: gltf,
primitive: primitive,
draco: draco,
gltfResource: gltfResource,
baseResource: baseResource,
cacheKey: cacheKey,
});
return ResourceCache.add(dracoLoader);
};
/**
* Gets an existing SPZ loader from the cache, or creates a new loader if one does not already exist.
* This loader is used to decode SPZ (Splat Point Cloud) data in glTF.
*
* @param {object} options Object with the following properties:
* @param {object} options.gltf The glTF JSON.
* @param {object} options.primitive The primitive containing the SPZ extension.
* @param {object} options.spz The SPZ extension object.
* @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
* @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
*
* @return {GltfSpzLoader} The cached SPZ loader.
@private
* */
ResourceCache.getSpzLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const { gltf, primitive, spz, gltfResource, baseResource } = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.gltf", gltf);
Check.typeOf.object("options.primitive", primitive);
Check.typeOf.object("options.spz", spz);
Check.typeOf.object("options.gltfResource", gltfResource);
Check.typeOf.object("options.baseResource", baseResource);
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getSpzCacheKey({
gltf: gltf,
primitive: primitive,
gltfResource: gltfResource,
baseResource: baseResource,
});
let spzLoader = ResourceCache.get(cacheKey);
if (defined(spzLoader)) {
return spzLoader;
}
spzLoader = new GltfSpzLoader({
resourceCache: ResourceCache,
gltf: gltf,
primitive: primitive,
spz: spz,
gltfResource: gltfResource,
baseResource: baseResource,
cacheKey: cacheKey,
});
return ResourceCache.add(spzLoader);
};
/**
* Gets an existing glTF vertex buffer from the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {object} options.gltf The glTF JSON.
* @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
* @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
* @param {FrameState} options.frameState The frame state.
* @param {number} [options.bufferViewId] The bufferView ID corresponding to the vertex buffer.
* @param {object} [options.primitive] The primitive containing the Draco extension.
* @param {object} [options.draco] The Draco extension object.
* @param {string} [options.attributeSemantic] The attribute semantic, e.g. POSITION or NORMAL.
* @param {number} [options.accessorId] The accessor ID.
* @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
* @param {boolean} [options.dequantize=false] Determines whether or not the vertex buffer will be dequantized on the CPU.
* @param {boolean} [options.loadBuffer=false] Load vertex buffer as a GPU vertex buffer.
* @param {boolean} [options.loadTypedArray=false] Load vertex buffer as a typed array.
* @exception {DeveloperError} One of options.bufferViewId and options.draco must be defined.
* @exception {DeveloperError} When options.draco is defined options.attributeSemantic must also be defined.
* @exception {DeveloperError} When options.draco is defined options.accessorId must also be defined.
*
* @returns {GltfVertexBufferLoader} The cached vertex buffer loader.
* @private
*/
ResourceCache.getVertexBufferLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const {
gltf,
gltfResource,
baseResource,
frameState,
bufferViewId,
primitive,
draco,
spz,
attributeSemantic,
accessorId,
asynchronous = true,
dequantize = false,
loadBuffer = false,
loadTypedArray = false,
} = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.gltf", gltf);
Check.typeOf.object("options.gltfResource", gltfResource);
Check.typeOf.object("options.baseResource", baseResource);
Check.typeOf.object("options.frameState", frameState);
if (!loadBuffer && !loadTypedArray) {
throw new DeveloperError(
"At least one of loadBuffer and loadTypedArray must be true.",
);
}
const hasBufferViewId = defined(bufferViewId);
const hasPrimitive = defined(primitive);
const hasDraco = hasDracoCompression(draco, attributeSemantic);
const hasAttributeSemantic = defined(attributeSemantic);
const hasAccessorId = defined(accessorId);
const hasSpz = defined(spz);
if (hasBufferViewId === (hasDraco !== hasSpz)) {
throw new DeveloperError(
"One of options.bufferViewId, options.draco, or options.spz must be defined.",
);
}
if (hasDraco && !hasAttributeSemantic) {
throw new DeveloperError(
"When options.draco is defined options.attributeSemantic must also be defined.",
);
}
if (hasDraco && !hasAccessorId) {
throw new DeveloperError(
"When options.draco is defined options.hasAccessorId must also be defined.",
);
}
if (hasDraco && !hasPrimitive) {
throw new DeveloperError(
"When options.draco is defined options.primitive must also be defined.",
);
}
if (hasDraco) {
Check.typeOf.object("options.draco", draco);
Check.typeOf.string("options.attributeSemantic", attributeSemantic);
Check.typeOf.number("options.accessorId", accessorId);
}
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getVertexBufferCacheKey({
gltf: gltf,
gltfResource: gltfResource,
baseResource: baseResource,
frameState: frameState,
bufferViewId: bufferViewId,
draco: draco,
spz: spz,
attributeSemantic: attributeSemantic,
dequantize: dequantize,
loadBuffer: loadBuffer,
loadTypedArray: loadTypedArray,
});
let vertexBufferLoader = ResourceCache.get(cacheKey);
if (defined(vertexBufferLoader)) {
return vertexBufferLoader;
}
vertexBufferLoader = new GltfVertexBufferLoader({
resourceCache: ResourceCache,
gltf: gltf,
gltfResource: gltfResource,
baseResource: baseResource,
bufferViewId: bufferViewId,
primitive: primitive,
draco: draco,
spz: spz,
attributeSemantic: attributeSemantic,
accessorId: accessorId,
cacheKey: cacheKey,
asynchronous: asynchronous,
dequantize: dequantize,
loadBuffer: loadBuffer,
loadTypedArray: loadTypedArray,
});
return ResourceCache.add(vertexBufferLoader);
};
function hasDracoCompression(draco, semantic) {
return (
defined(draco) &&
defined(draco.attributes) &&
defined(draco.attributes[semantic])
);
}
/**
* Gets an existing glTF index buffer from the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {object} options.gltf The glTF JSON.
* @param {number} options.accessorId The accessor ID corresponding to the index buffer.
* @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
* @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
* @param {FrameState} options.frameState The frame state.
* @param {object} [options.primitive] The primitive containing the Draco extension.
* @param {object} [options.draco] The Draco extension object.
* @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
* @param {boolean} [options.loadBuffer=false] Load index buffer as a GPU index buffer.
* @param {boolean} [options.loadTypedArray=false] Load index buffer as a typed array.
* @returns {GltfIndexBufferLoader} The cached index buffer loader.
* @private
*/
ResourceCache.getIndexBufferLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const {
gltf,
accessorId,
gltfResource,
baseResource,
frameState,
primitive,
draco,
asynchronous = true,
loadBuffer = false,
loadTypedArray = false,
} = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.gltf", gltf);
Check.typeOf.number("options.accessorId", accessorId);
Check.typeOf.object("options.gltfResource", gltfResource);
Check.typeOf.object("options.baseResource", baseResource);
Check.typeOf.object("options.frameState", frameState);
if (!loadBuffer && !loadTypedArray) {
throw new DeveloperError(
"At least one of loadBuffer and loadTypedArray must be true.",
);
}
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getIndexBufferCacheKey({
gltf: gltf,
accessorId: accessorId,
gltfResource: gltfResource,
baseResource: baseResource,
frameState: frameState,
draco: draco,
loadBuffer: loadBuffer,
loadTypedArray: loadTypedArray,
});
let indexBufferLoader = ResourceCache.get(cacheKey);
if (defined(indexBufferLoader)) {
return indexBufferLoader;
}
indexBufferLoader = new GltfIndexBufferLoader({
resourceCache: ResourceCache,
gltf: gltf,
accessorId: accessorId,
gltfResource: gltfResource,
baseResource: baseResource,
primitive: primitive,
draco: draco,
cacheKey: cacheKey,
asynchronous: asynchronous,
loadBuffer: loadBuffer,
loadTypedArray: loadTypedArray,
});
return ResourceCache.add(indexBufferLoader);
};
/**
* Gets an existing glTF image from the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {object} options.gltf The glTF JSON.
* @param {number} options.imageId The image ID.
* @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
* @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
*
* @returns {GltfImageLoader} The cached image loader.
* @private
*/
ResourceCache.getImageLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const { gltf, imageId, gltfResource, baseResource } = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.gltf", gltf);
Check.typeOf.number("options.imageId", imageId);
Check.typeOf.object("options.gltfResource", gltfResource);
Check.typeOf.object("options.baseResource", baseResource);
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getImageCacheKey({
gltf: gltf,
imageId: imageId,
gltfResource: gltfResource,
baseResource: baseResource,
});
let imageLoader = ResourceCache.get(cacheKey);
if (defined(imageLoader)) {
return imageLoader;
}
imageLoader = new GltfImageLoader({
resourceCache: ResourceCache,
gltf: gltf,
imageId: imageId,
gltfResource: gltfResource,
baseResource: baseResource,
cacheKey: cacheKey,
});
return ResourceCache.add(imageLoader);
};
/**
* Gets an existing glTF texture from the cache, or creates a new loader if one does not already exist.
*
* @param {object} options Object with the following properties:
* @param {object} options.gltf The glTF JSON.
* @param {object} options.textureInfo The texture info object.
* @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
* @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
* @param {SupportedImageFormats} options.supportedImageFormats The supported image formats.
* @param {FrameState} options.frameState The frame state.
* @param {boolean} [options.asynchronous=true] Determines if WebGL resource creation will be spread out over several frames or block until all WebGL resources are created.
*
* @returns {GltfTextureLoader} The cached texture loader.
* @private
*/
ResourceCache.getTextureLoader = function (options) {
options = options ?? Frozen.EMPTY_OBJECT;
const {
gltf,
textureInfo,
gltfResource,
baseResource,
supportedImageFormats,
frameState,
asynchronous = true,
} = options;
//>>includeStart('debug', pragmas.debug);
Check.typeOf.object("options.gltf", gltf);
Check.typeOf.object("options.textureInfo", textureInfo);
Check.typeOf.object("options.gltfResource", gltfResource);
Check.typeOf.object("options.baseResource", baseResource);
Check.typeOf.object("options.supportedImageFormats", supportedImageFormats);
Check.typeOf.object("options.frameState", frameState);
//>>includeEnd('debug');
const cacheKey = ResourceCacheKey.getTextureCacheKey({
gltf: gltf,
textureInfo: textureInfo,
gltfResource: gltfResource,
baseResource: baseResource,
supportedImageFormats: supportedImageFormats,
frameState: frameState,
});
let textureLoader = ResourceCache.get(cacheKey);
if (defined(textureLoader)) {
return textureLoader;
}
textureLoader = new GltfTextureLoader({
resourceCache: ResourceCache,
gltf: gltf,
textureInfo: textureInfo,
gltfResource: gltfResource,
baseResource: baseResource,
supportedImageFormats: supportedImageFormats,
cacheKey: cacheKey,
asynchronous: asynchronous,
});
return ResourceCache.add(textureLoader);
};
/**
* Unload everything from the cache. This is used for unit testing.
*
* @private
*/
ResourceCache.clearForSpecs = function () {
// Unload in the order below. This prevents an unload function from unloading
// a resource that has already been unloaded.
const precedence = [
GltfVertexBufferLoader,
GltfIndexBufferLoader,
GltfDracoLoader,
GltfTextureLoader,
GltfImageLoader,
GltfBufferViewLoader,
BufferLoader,
MetadataSchemaLoader,
GltfJsonLoader,
];
let cacheKey;
const cacheEntries = ResourceCache.cacheEntries;
const cacheEntriesSorted = [];
for (cacheKey in cacheEntries) {
if (cacheEntries.hasOwnProperty(cacheKey)) {
cacheEntriesSorted.push(cacheEntries[cacheKey]);
}
}
cacheEntriesSorted.sort(function (a, b) {
const indexA = precedence.indexOf(a.resourceLoader.constructor);
const indexB = precedence.indexOf(b.resourceLoader.constructor);
return indexA - indexB;
});
const cacheEntriesLength = cacheEntriesSorted.length;
for (let i = 0; i < cacheEntriesLength; ++i) {
const cacheEntry = cacheEntriesSorted[i];
cacheKey = cacheEntry.resourceLoader.cacheKey;
if (defined(cacheEntries[cacheKey])) {
cacheEntry.resourceLoader.destroy();
delete cacheEntries[cacheKey];
}
}
ResourceCache.statistics.clear();
};
export default ResourceCache;