Skip to content

Commit

Permalink
GLBRangeRequests: Optimize
Browse files Browse the repository at this point in the history
  • Loading branch information
takahirox committed Oct 20, 2022
1 parent 2c7d451 commit 3db115a
Showing 1 changed file with 31 additions and 15 deletions.
46 changes: 31 additions & 15 deletions loaders/GLB_range_requests/GLB_range_requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,29 @@ export default class GLBRangeRequests {
content.binChunkOffset
))
.parse(content.jsonContent, resourcePath, onLoad, onError);
}).catch(() => {
}).catch((error) => {
// 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
// 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
// if the error reason is others?

// console.log(error);
loader.load(url, onLoad, onProgress, onError);
});
}

// Note: Rejects if server doesn't support HTTP range requests
static async loadContent(url, fileLoader = null) {
if (fileLoader === null) {
fileLoader = new FileLoader().setResponseType('arraybuffer');
}

const buffer = await loadPartially(fileLoader, url, 0, BINARY_HEADER_LENGTH);
// Load the GLB header and the first chunk info
const buffer = await loadPartially(fileLoader, url, 0, BINARY_HEADER_LENGTH + 8);
const view = new DataView(buffer);
const header = {
magic: LoaderUtils.decodeText(new Uint8Array(buffer.slice(0, 4))),
Expand All @@ -83,27 +89,37 @@ export default class GLBRangeRequests {
return Promise.reject(new Error('GLBRangeRequests: Legacy binary file detected.'));
}

const firstChunkLength = view.getUint32(12, true);
const firstChunkType = view.getUint32(16, true);

const result = {
jsonContent: null,
binChunkOffset: null
};

let offset = BINARY_HEADER_LENGTH;
let offset = BINARY_HEADER_LENGTH + 8;

while (offset < header.length) {
const buffer = await loadPartially(fileLoader, url, offset, 8);
const view = new DataView(buffer);
const length = view.getUint32(0, true);
const type = view.getUint32(4, true);
offset += 8;
if (firstChunkType === BINARY_CHUNK_TYPES.JSON) {
result.jsonContent = await loadPartially(fileLoader, url, offset, firstChunkLength);
} else if (firstChunkType === BINARY_CHUNK_TYPES.BIN) {
result.binChunkOffset = offset;
}

if (type === BINARY_CHUNK_TYPES.JSON) {
result.jsonContent = await loadPartially(fileLoader, url, offset, length);
} else if (type === BINARY_CHUNK_TYPES.BIN) {
result.binChunkOffset = offset;
offset += firstChunkLength;

// The number of json chunks must be 1. The number of bin chunks must be 0 or 1.

This comment has been minimized.

Copy link
@netpro2k

netpro2k Oct 21, 2022

It is invalid for the JSON chunk not to be first for this exact usecase https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#structured-json-content

This chunk MUST be the very first chunk of a Binary glTF asset. By reading this chunk first, an implementation is able to progressively retrieve resources from subsequent chunks. This way, it is also possible to read only a selected subset of resources from a Binary glTF asset.

So I think this can be simplified a bit to

if (firstChunkType === BINARY_CHUNK_TYPES.JSON) return Promise.reject(new Error('GLBRangeRequests: Invalid GLB file. The JSON chunk MUST come first.'));
result.jsonContent = await loadPartially(fileLoader, url, offset, firstChunkLength);
result.binChunkOffset = offset + firstChunkLength + 8;

This comment has been minimized.

Copy link
@takahirox

takahirox Oct 25, 2022

Author Owner

It is invalid for the JSON chunk not to be first for this exact usecase

Thanks, I had overlooked it. I will update the implementation.

This comment has been minimized.

Copy link
@takahirox

takahirox Oct 25, 2022

Author Owner

Done, thanks

// So, if the second chunk exists the second chunk can be guessed from the first
// chunk type.
// Note: Assuming the GLB format is valid
if (offset < header.length) {
if (result.jsonContent === null) {
const buffer = await loadPartially(fileLoader, url, offset, 4);
const view = new DataView(buffer);
const length = view.getUint32(0, true);
result.jsonContent = await loadPartially(fileLoader, url, offset + 8, length);
} else {
result.binChunkOffset = offset + 8;
}

offset += length;
}

if (result.jsonContent.extensionsUsed &&
Expand Down

0 comments on commit 3db115a

Please sign in to comment.