Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GLBRangeRequests: Avoid duplicated full content download #90

Merged
merged 1 commit into from
Oct 26, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 55 additions & 11 deletions loaders/GLB_range_requests/GLB_range_requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,39 @@ const loadPartially = (fileLoader, url, offset, length) => {
});
};

// Based on the code in FileLoader
// Used if server doesn't support HTTP range requests.
const loadArrayBufferFromResponse = (response, onProgress) => {
const reader = response.body.getReader();
const contentLength = response.headers.get('Content-Length');
const total = contentLength ? parseInt(contentLength) : 0;
const lengthComputable = total !== 0;
let loaded = 0;

// periodically read data into the new stream tracking while download progress
return new Response(
new ReadableStream({
start(controller) {
readData();
function readData() {
reader.read().then(({done, value}) => {
if (done) {
controller.close();
} else {
loaded += value.byteLength;
const event = new ProgressEvent('progress', {lengthComputable, loaded, total});
if (onProgress) onProgress(event);
controller.enqueue(value);
readData();
}
});
}
}
})
).arrayBuffer();
};


// GLB File Format handlers
// Specification: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#glb-file-format-specification

Expand All @@ -34,16 +67,16 @@ export default class GLBRangeRequests {

static load(url, loader, onLoad, onProgress, onError, fileLoader = null) {
const assetUrl = (loader.path || '') + url;
GLBRangeRequests.loadContent(assetUrl, fileLoader).then(content => {
let resourcePath;
if (loader.resourcePath !== '') {
resourcePath = loader.resourcePath;
} else if (loader.path !== '') {
resourcePath = loader.path;
} else {
resourcePath = LoaderUtils.extractUrlBase(assetUrl);
}
let resourcePath;
if (loader.resourcePath !== '') {
resourcePath = loader.resourcePath;
} else if (loader.path !== '') {
resourcePath = loader.path;
} else {
resourcePath = LoaderUtils.extractUrlBase(assetUrl);
}

GLBRangeRequests.loadContent(assetUrl, fileLoader).then(content => {
loader
.register(parser => new GLBRangeRequests(
parser,
Expand All @@ -52,10 +85,21 @@ export default class GLBRangeRequests {
))
.parse(content.jsonContent, resourcePath, onLoad, onError);
}).catch((error) => {
// If server doesn't support range requests.
// Response has full range content.
// Parse with the full range content as fallback.
if (error.response && error.response.status === 200) {
loadArrayBufferFromResponse(error.response, onProgress).then(buffer => {
loader.parse(buffer, resourcePath, onLoad, onError);
}).catch(error => {
if (onError) onError(error);
});
return;
}

// Perhaps rejected due to the either one
// 1. The asset is not GLB (but glTF)
// 2. Server may not support HTTP range requests
// 3. The asset includes EXT_meshopt_compression extension that the
// 2. The asset includes EXT_meshopt_compression extension that the
// this plugin can't handle
// so load in the regular way as fallback.
// @TODO: Check the error reason and don't run the fallback loading
Expand Down