Add existing to tracked
This commit is contained in:
+231
@@ -0,0 +1,231 @@
|
||||
import Check from "../Core/Check.js";
|
||||
import Frozen from "../Core/Frozen.js";
|
||||
import defined from "../Core/defined.js";
|
||||
import findMeshoptExtension from "./findMeshoptExtension.js";
|
||||
import { MeshoptDecoder } from "meshoptimizer";
|
||||
import ResourceLoader from "./ResourceLoader.js";
|
||||
import ResourceLoaderState from "./ResourceLoaderState.js";
|
||||
|
||||
/**
|
||||
* Loads a glTF buffer view.
|
||||
* <p>
|
||||
* Implements the {@link ResourceLoader} interface.
|
||||
* </p>
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
class GltfBufferViewLoader extends ResourceLoader {
|
||||
/**
|
||||
* @param {object} options Object with the following properties:
|
||||
* @param {ResourceCache} options.resourceCache The {@link ResourceCache} (to avoid circular dependencies).
|
||||
* @param {object} options.gltf The glTF JSON.
|
||||
* @param {number} options.bufferViewId The buffer view 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.
|
||||
* @param {string} [options.cacheKey] The cache key of the resource.
|
||||
*/
|
||||
constructor(options) {
|
||||
super();
|
||||
|
||||
options = options ?? Frozen.EMPTY_OBJECT;
|
||||
const resourceCache = options.resourceCache;
|
||||
const gltf = options.gltf;
|
||||
const bufferViewId = options.bufferViewId;
|
||||
const gltfResource = options.gltfResource;
|
||||
const baseResource = options.baseResource;
|
||||
const cacheKey = options.cacheKey;
|
||||
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.typeOf.func("options.resourceCache", resourceCache);
|
||||
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 bufferView = gltf.bufferViews[bufferViewId];
|
||||
let bufferId = bufferView.buffer;
|
||||
let byteOffset = bufferView.byteOffset;
|
||||
let byteLength = bufferView.byteLength;
|
||||
|
||||
let hasMeshopt = false;
|
||||
let meshoptByteStride;
|
||||
let meshoptCount;
|
||||
let meshoptMode;
|
||||
let meshoptFilter;
|
||||
|
||||
const meshopt = findMeshoptExtension(bufferView);
|
||||
if (defined(meshopt)) {
|
||||
bufferId = meshopt.buffer;
|
||||
byteOffset = meshopt.byteOffset ?? 0;
|
||||
byteLength = meshopt.byteLength;
|
||||
|
||||
hasMeshopt = true;
|
||||
meshoptByteStride = meshopt.byteStride;
|
||||
meshoptCount = meshopt.count;
|
||||
meshoptMode = meshopt.mode;
|
||||
meshoptFilter = meshopt.filter ?? "NONE";
|
||||
}
|
||||
|
||||
const buffer = gltf.buffers[bufferId];
|
||||
|
||||
this._hasMeshopt = hasMeshopt;
|
||||
this._meshoptByteStride = meshoptByteStride;
|
||||
this._meshoptCount = meshoptCount;
|
||||
this._meshoptMode = meshoptMode;
|
||||
this._meshoptFilter = meshoptFilter;
|
||||
|
||||
this._resourceCache = resourceCache;
|
||||
this._gltfResource = gltfResource;
|
||||
this._baseResource = baseResource;
|
||||
this._buffer = buffer;
|
||||
this._bufferId = bufferId;
|
||||
this._byteOffset = byteOffset;
|
||||
this._byteLength = byteLength;
|
||||
this._cacheKey = cacheKey;
|
||||
this._bufferLoader = undefined;
|
||||
this._typedArray = undefined;
|
||||
this._state = ResourceLoaderState.UNLOADED;
|
||||
this._promise = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache key of the resource.
|
||||
*
|
||||
*
|
||||
* @type {string}
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
get cacheKey() {
|
||||
return this._cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* The typed array containing buffer view data.
|
||||
*
|
||||
*
|
||||
* @type {Uint8Array}
|
||||
* @readonly
|
||||
* @private
|
||||
*/
|
||||
get typedArray() {
|
||||
return this._typedArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the resource.
|
||||
* @returns {Promise<GltfBufferViewLoader>} A promise which resolves to the loader when the resource loading is completed.
|
||||
* @private
|
||||
*/
|
||||
async load() {
|
||||
if (defined(this._promise)) {
|
||||
return this._promise;
|
||||
}
|
||||
|
||||
this._state = ResourceLoaderState.LOADING;
|
||||
this._promise = loadResources(this);
|
||||
return this._promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads the resource.
|
||||
* @private
|
||||
*/
|
||||
unload() {
|
||||
if (defined(this._bufferLoader) && !this._bufferLoader.isDestroyed()) {
|
||||
this._resourceCache.unload(this._bufferLoader);
|
||||
}
|
||||
|
||||
this._bufferLoader = undefined;
|
||||
this._typedArray = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the resources associated with the loader.
|
||||
* @private
|
||||
* @param {GltfBufferViewLoader} loader
|
||||
* @returns {Promise<GltfBufferViewLoader>}
|
||||
*/
|
||||
async function loadResources(loader) {
|
||||
try {
|
||||
const bufferLoader = getBufferLoader(loader);
|
||||
loader._bufferLoader = bufferLoader;
|
||||
await bufferLoader.load();
|
||||
|
||||
if (loader.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bufferTypedArray = bufferLoader.typedArray;
|
||||
const bufferViewTypedArray = new Uint8Array(
|
||||
bufferTypedArray.buffer,
|
||||
bufferTypedArray.byteOffset + loader._byteOffset,
|
||||
loader._byteLength,
|
||||
);
|
||||
|
||||
// Unload the buffer
|
||||
loader.unload();
|
||||
|
||||
loader._typedArray = bufferViewTypedArray;
|
||||
if (loader._hasMeshopt) {
|
||||
const count = loader._meshoptCount;
|
||||
const byteStride = loader._meshoptByteStride;
|
||||
const result = new Uint8Array(count * byteStride);
|
||||
MeshoptDecoder.decodeGltfBuffer(
|
||||
result,
|
||||
count,
|
||||
byteStride,
|
||||
loader._typedArray,
|
||||
loader._meshoptMode,
|
||||
loader._meshoptFilter,
|
||||
);
|
||||
loader._typedArray = result;
|
||||
}
|
||||
|
||||
loader._state = ResourceLoaderState.READY;
|
||||
return loader;
|
||||
} catch (error) {
|
||||
if (loader.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
loader.unload();
|
||||
loader._state = ResourceLoaderState.FAILED;
|
||||
const errorMessage = "Failed to load buffer view";
|
||||
throw loader.getError(errorMessage, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the buffer loader for the specified buffer view loader.
|
||||
* Attempts to retrieve from the resource cache first. If a buffer loader is
|
||||
* not found, creates a new buffer loader and adds it to the resource cache.
|
||||
* @private
|
||||
* @param {GltfBufferViewLoader} bufferViewLoader The loader.
|
||||
* @returns {BufferLoader} The buffer loader.
|
||||
*/
|
||||
function getBufferLoader(bufferViewLoader) {
|
||||
const resourceCache = bufferViewLoader._resourceCache;
|
||||
const buffer = bufferViewLoader._buffer;
|
||||
|
||||
if (defined(buffer.uri)) {
|
||||
const baseResource = bufferViewLoader._baseResource;
|
||||
const resource = baseResource.getDerivedResource({
|
||||
url: buffer.uri,
|
||||
});
|
||||
return resourceCache.getExternalBufferLoader({
|
||||
resource: resource,
|
||||
});
|
||||
}
|
||||
|
||||
const source = buffer.extras?._pipeline?.source;
|
||||
return resourceCache.getEmbeddedBufferLoader({
|
||||
parentResource: bufferViewLoader._gltfResource,
|
||||
bufferId: bufferViewLoader._bufferId,
|
||||
typedArray: source,
|
||||
});
|
||||
}
|
||||
|
||||
export default GltfBufferViewLoader;
|
||||
Reference in New Issue
Block a user