UNPKG

@inweb/viewer-three

Version:

JavaScript library for rendering CAD and BIM files in a browser using Three.js

151 lines (120 loc) 5.7 kB
/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a // license agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// import { FileLoader, Group, LoaderUtils } from "three"; import { Loader } from "@inweb/viewer-core"; import { Viewer } from "../Viewer"; import { DynamicModelImpl } from "./DynamicGltfLoader/DynamicModelImpl"; import { DynamicGltfLoader } from "./DynamicGltfLoader/DynamicGltfLoader.js"; import { GltfStructure } from "./DynamicGltfLoader/GltfStructure.js"; import { GLTFLoadingManager, GLTFLoadParams } from "./GLTFLoadingManager"; import { GLTFBinaryExtension } from "./GLTFBinaryExtension"; import { RangesLoader } from "./RangesLoader"; export class GLTFFileDynamicLoader extends Loader { public viewer: Viewer; private gltfLoader: DynamicGltfLoader; private manager: GLTFLoadingManager; private gltf: any; private glb: ArrayBuffer; constructor(viewer: Viewer) { super(); this.viewer = viewer; } override dispose() { if (this.gltfLoader) this.gltfLoader.clear(); if (this.manager) this.manager.dispose(); } override isSupport(file: any, format?: string): boolean { return ( (typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) && /(gltf|glb)$/i.test(format) ); } override async load(file: any, format?: string, params?: GLTFLoadParams): Promise<this> { this.manager = new GLTFLoadingManager(file, params); const scene = new Group(); this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer); this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit; this.gltfLoader.visibleEdges = this.viewer.options.edgeModel; const modelImpl = new DynamicModelImpl(scene); modelImpl.id = params.modelId || this.extractFileName(file); modelImpl.gltfLoader = this.gltfLoader; this.gltfLoader.addEventListener("databasechunk", () => { this.viewer.scene.add(scene); this.viewer.models.push(modelImpl); this.viewer.syncOptions(); this.viewer.syncOverlay(); this.viewer.emitEvent({ type: "databasechunk", data: scene, file }); this.viewer.update(true); }); this.gltfLoader.addEventListener("geometryerror", (data) => { this.viewer.emitEvent({ type: "geometryerror", data, file }); }); this.gltfLoader.addEventListener("update", () => { this.viewer.update(); }); const loadController = { loadJson: async () => { const loader = new FileLoader(this.manager); loader.setPath(this.manager.path); loader.setRequestHeader((params.requestHeader as any) || {}); loader.setWithCredentials(params.withCredentials || loader.withCredentials); loader.setResponseType("arraybuffer"); const progress = (event: ProgressEvent) => { const { lengthComputable, loaded, total } = event; const progress = lengthComputable ? loaded / total : 1; this.viewer.emitEvent({ type: "geometryprogress", data: progress, file }); }; const data = await loader.loadAsync(this.manager.fileURL, progress); const extension = new GLTFBinaryExtension(data as ArrayBuffer); this.gltf = JSON.parse(extension.content); this.glb = extension.body; if (/\.glb$/i.test(this.manager.fileURL) && !this.glb) { throw new Error("GLTFFileDynamicLoader: Binary buffer chunk not found or type not supported."); } return this.gltf; }, loadBinaryData: (ranges, uri = "") => { const loader = new RangesLoader(); loader.setRequestHeader((params.requestHeader as any) || {}); loader.setWithCredentials(params.withCredentials || false); loader.setAbortSignal(this.gltfLoader.abortController.signal); if (this.glb) return loader.extractRanges(this.glb, ranges); const path = this.manager.path || this.manager.resourcePath; const url = LoaderUtils.resolveURL(uri, path); return loader.load(this.manager.resolveURL(url), ranges); }, resolveURL: (uri) => { const path = this.manager.path || this.manager.resourcePath; const url = LoaderUtils.resolveURL(uri, path); return Promise.resolve(this.manager.resolveURL(url)); }, }; const structure = new GltfStructure(modelImpl.id, loadController); await this.gltfLoader.loadStructure(structure); await this.gltfLoader.loadNodes(); return this; } override cancel() { if (this.gltfLoader) this.gltfLoader.abortLoading(); } }