Reference Source

src/plugins/GLTFLoaderPlugin/GLTFDefaultDataSource.js

import {utils} from "../../viewer/scene/utils.js";
import {core} from "../../viewer/scene/core.js";

/**
 * Default data access strategy for {@link GLTFLoaderPlugin}.
 *
 * This just loads assets using XMLHttpRequest.
 */
class GLTFDefaultDataSource {

    constructor(cfg = {}) {
        this.cacheBuster = (cfg.cacheBuster !== false);
    }

    _cacheBusterURL(url) {
        if (!this.cacheBuster) {
            return url;
        }
        const timestamp = new Date().getTime();
        if (url.indexOf('?') > -1) {
            return url + '&_=' + timestamp;
        } else {
            return url + '?_=' + timestamp;
        }
    }

    /**
     * Gets metamodel JSON.
     *
     * @param {String|Number} metaModelSrc Identifies the metamodel JSON asset.
     * @param {Function} ok Fired on successful loading of the metamodel JSON asset.
     * @param {Function} error Fired on error while loading the metamodel JSON asset.
     */
    getMetaModel(metaModelSrc, ok, error) {
        utils.loadJSON(this._cacheBusterURL(metaModelSrc),
            (json) => {
                ok(json);
            },
            function (errMsg) {
                error(errMsg);
            });
    }

    /**
     * Gets glTF JSON.
     *
     * @param {String|Number} glTFSrc Identifies the glTF JSON asset.
     * @param {Function} ok Fired on successful loading of the glTF JSON asset.
     * @param {Function} error Fired on error while loading the glTF JSON asset.
     */
    getGLTF(glTFSrc, ok, error) {
        utils.loadArraybuffer(this._cacheBusterURL(glTFSrc),
            (gltf) => {
                ok(gltf);
            },
            function (errMsg) {
                error(errMsg);
            });
    }

    /**
     * Gets binary glTF file.
     *
     * @param {String|Number} glbSrc Identifies the .glb asset.
     * @param {Function} ok Fired on successful loading of the .glb asset.
     * @param {Function} error Fired on error while loading the .glb asset.
     */
    getGLB(glbSrc, ok, error) {
        utils.loadArraybuffer(this._cacheBusterURL(glbSrc),
            (arraybuffer) => {
                ok(arraybuffer);
            },
            function (errMsg) {
                error(errMsg);
            });
    }

    /**
     * Gets glTF binary attachment.
     *
     * Note that this method requires the source of the glTF JSON asset. This is because the binary attachment
     * source could be relative to the glTF source, IE. it may not be a global ID.
     *
     * @param {String|Number} glTFSrc Identifies the glTF JSON asset.
     * @param {String|Number} binarySrc Identifies the glTF binary asset.
     * @param {Function} ok Fired on successful loading of the glTF binary asset.
     * @param {Function} error Fired on error while loading the glTF binary asset.
     */
    getArrayBuffer(glTFSrc, binarySrc, ok, error) {
        loadArraybuffer(this._cacheBusterURL(glTFSrc), binarySrc,
            (arrayBuffer) => {
                ok(arrayBuffer);
            },
            function (errMsg) {
                error(errMsg);
            });
    }
}

function loadArraybuffer(glTFSrc, binarySrc, ok, err) {
    // Check for data: URI
    var defaultCallback = () => {
    };
    ok = ok || defaultCallback;
    err = err || defaultCallback;
    const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
    const dataUriRegexResult = binarySrc.match(dataUriRegex);
    if (dataUriRegexResult) { // Safari can't handle data URIs through XMLHttpRequest
        const isBase64 = !!dataUriRegexResult[2];
        var data = dataUriRegexResult[3];
        data = window.decodeURIComponent(data);
        if (isBase64) {
            data = window.atob(data);
        }
        try {
            const buffer = new ArrayBuffer(data.length);
            const view = new Uint8Array(buffer);
            for (var i = 0; i < data.length; i++) {
                view[i] = data.charCodeAt(i);
            }
            core.scheduleTask(function () {
                ok(buffer);
            });
        } catch (error) {
            core.scheduleTask(function () {
                err(error);
            });
        }
    } else {
        const basePath = getBasePath(glTFSrc);
        const url = basePath + binarySrc;
        const request = new XMLHttpRequest();
        request.open('GET', url, true);
        request.responseType = 'arraybuffer';
        request.onreadystatechange = function () {
            if (request.readyState === 4) {
                if (request.status === 200) {
                    ok(request.response);
                } else {
                    err('loadArrayBuffer error : ' + request.response);
                }
            }
        };
        request.send(null);
    }
}

function getBasePath(src) {
    var i = src.lastIndexOf("/");
    return (i !== 0) ? src.substring(0, i + 1) : "";
}

export {GLTFDefaultDataSource};