Add existing to tracked
This commit is contained in:
+827
@@ -0,0 +1,827 @@
|
||||
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,
|
||||
spz: spz,
|
||||
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 {object} [options.spz] The SPZ 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} Exactly one vertex buffer source must be effective: options.bufferViewId, options.spz, or options.draco for options.attributeSemantic.
|
||||
* @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);
|
||||
|
||||
const sourceCount =
|
||||
Number(hasBufferViewId) + Number(hasDraco) + Number(hasSpz);
|
||||
if (sourceCount !== 1) {
|
||||
throw new DeveloperError(
|
||||
"Exactly one vertex buffer source must be effective: options.bufferViewId, options.spz, or options.draco for options.attributeSemantic.",
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
Reference in New Issue
Block a user