761 lines
25 KiB
JavaScript
761 lines
25 KiB
JavaScript
import Check from "../Core/Check.js";
|
|
import defaultValue from "../Core/defaultValue.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 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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const schema = options.schema;
|
|
const resource = options.resource;
|
|
|
|
//>>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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const parentResource = options.parentResource;
|
|
const bufferId = options.bufferId;
|
|
const typedArray = options.typedArray;
|
|
|
|
//>>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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const resource = options.resource;
|
|
|
|
//>>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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const gltfResource = options.gltfResource;
|
|
const baseResource = options.baseResource;
|
|
const typedArray = options.typedArray;
|
|
const gltfJson = options.gltfJson;
|
|
|
|
//>>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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const gltf = options.gltf;
|
|
const bufferViewId = options.bufferViewId;
|
|
const gltfResource = options.gltfResource;
|
|
const baseResource = options.baseResource;
|
|
|
|
//>>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.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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const gltf = options.gltf;
|
|
const draco = options.draco;
|
|
const gltfResource = options.gltfResource;
|
|
const baseResource = options.baseResource;
|
|
|
|
//>>includeStart('debug', pragmas.debug);
|
|
Check.typeOf.object("options.gltf", gltf);
|
|
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,
|
|
draco: draco,
|
|
gltfResource: gltfResource,
|
|
baseResource: baseResource,
|
|
cacheKey: cacheKey,
|
|
});
|
|
|
|
return ResourceCache.add(dracoLoader);
|
|
};
|
|
|
|
/**
|
|
* 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.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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const gltf = options.gltf;
|
|
const gltfResource = options.gltfResource;
|
|
const baseResource = options.baseResource;
|
|
const frameState = options.frameState;
|
|
const bufferViewId = options.bufferViewId;
|
|
const draco = options.draco;
|
|
const attributeSemantic = options.attributeSemantic;
|
|
const accessorId = options.accessorId;
|
|
const asynchronous = defaultValue(options.asynchronous, true);
|
|
const dequantize = defaultValue(options.dequantize, false);
|
|
const loadBuffer = defaultValue(options.loadBuffer, false);
|
|
const loadTypedArray = defaultValue(options.loadTypedArray, false);
|
|
|
|
//>>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 hasDraco = hasDracoCompression(draco, attributeSemantic);
|
|
const hasAttributeSemantic = defined(attributeSemantic);
|
|
const hasAccessorId = defined(accessorId);
|
|
|
|
if (hasBufferViewId === hasDraco) {
|
|
throw new DeveloperError(
|
|
"One of options.bufferViewId and options.draco 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.haAccessorId 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,
|
|
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,
|
|
draco: draco,
|
|
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.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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const gltf = options.gltf;
|
|
const accessorId = options.accessorId;
|
|
const gltfResource = options.gltfResource;
|
|
const baseResource = options.baseResource;
|
|
const frameState = options.frameState;
|
|
const draco = options.draco;
|
|
const asynchronous = defaultValue(options.asynchronous, true);
|
|
const loadBuffer = defaultValue(options.loadBuffer, false);
|
|
const loadTypedArray = defaultValue(options.loadTypedArray, false);
|
|
|
|
//>>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,
|
|
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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const gltf = options.gltf;
|
|
const imageId = options.imageId;
|
|
const gltfResource = options.gltfResource;
|
|
const baseResource = options.baseResource;
|
|
|
|
//>>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 = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
const gltf = options.gltf;
|
|
const textureInfo = options.textureInfo;
|
|
const gltfResource = options.gltfResource;
|
|
const baseResource = options.baseResource;
|
|
const supportedImageFormats = options.supportedImageFormats;
|
|
const frameState = options.frameState;
|
|
const asynchronous = defaultValue(options.asynchronous, true);
|
|
|
|
//>>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;
|