import type { AnimationClip, Material, Scene } from 'three' import type { GLTF } from 'three-stdlib' import { type TresLoader, type TresObject3D, useLoader } from '@tresjs/core' import { DRACOLoader, GLTFLoader } from 'three-stdlib' export interface GLTFLoaderOptions { /** * Whether to use Draco compression. * * @type {boolean} * @memberof GLTFLoaderOptions */ draco?: boolean /** * The path to the Draco decoder. * * @type {string} * @memberof GLTFLoaderOptions */ decoderPath?: string } export interface GLTFResult { animations: Array nodes: Record materials: Record scene: Scene } let dracoLoader: DRACOLoader | null = null export interface TresGLTFLoader extends TresLoader { setDRACOLoader?: (dracoLoader: DRACOLoader) => void } /** * Sets the extensions for the GLTFLoader. * * @param {GLTFLoaderOptions} options * @param {(loader: TresGLTFLoader) => void} [extendLoader] * @return {*} */ function setExtensions(options: GLTFLoaderOptions, extendLoader?: (loader: TresGLTFLoader) => void) { return (loader: TresGLTFLoader) => { if (extendLoader) { extendLoader(loader) } if (options.draco) { if (!dracoLoader) { dracoLoader = new DRACOLoader() } dracoLoader.setDecoderPath(options.decoderPath || 'https://www.gstatic.com/draco/versioned/decoders/1.4.3/') if (loader.setDRACOLoader) { loader.setDRACOLoader(dracoLoader) } } } } /** * Loads a GLTF file and returns a THREE.Object3D. * * @export * @param {(string | string[])} path * @param {GLTFLoaderOptions} [options] * * * @param {(loader: GLTFLoader) => void} [extendLoader] * @return {*} {Promise} */ export async function useGLTF( path: T, options: GLTFLoaderOptions = { draco: false, }, extendLoader?: (loader: TresGLTFLoader) => void, ): Promise { const gltfModel = (await useLoader(GLTFLoader, path, setExtensions(options, extendLoader))) as unknown as GLTFResult dracoLoader?.dispose() dracoLoader = null return gltfModel as T extends string[] ? GLTFResult[] : GLTFResult }