index.ts 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import { isArray } from '@alvarosabu/utils'
  2. import { Object3D } from 'three'
  3. import { useLogger } from '/@/composables'
  4. export interface TresLoader<T> extends THREE.Loader {
  5. load(
  6. url: string,
  7. onLoad?: (result: T) => void,
  8. onProgress?: (event: ProgressEvent) => void,
  9. onError?: (event: ErrorEvent) => void,
  10. ): unknown
  11. loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise<T>
  12. }
  13. export type LoaderProto<T> = new (...args: any) => TresLoader<T extends unknown ? any : T>
  14. export type LoaderReturnType<T, L extends LoaderProto<T>> = T extends unknown
  15. ? Awaited<ReturnType<InstanceType<L>['loadAsync']>>
  16. : T
  17. export function trasverseObjects(object: Object3D) {
  18. const data: { [key: string]: any } = { nodes: {}, materials: {} }
  19. if (object) {
  20. object.traverse((obj: any) => {
  21. if (obj.name) {
  22. data.nodes[obj.name] = obj
  23. }
  24. if (obj.material && !data.materials[obj.material.name]) {
  25. data.materials[obj.material.name] = obj.material
  26. }
  27. })
  28. }
  29. return data
  30. }
  31. export type Extensions<T extends { prototype: LoaderProto<any> }> = (loader: T['prototype']) => void
  32. export async function useLoader<T extends LoaderProto<T>, U extends string | string[]>(
  33. Loader: T,
  34. url: U,
  35. extensions?: Extensions<T>,
  36. onProgress?: (event: ProgressEvent<EventTarget>) => void,
  37. cb?: (proto: TresLoader<T>) => void,
  38. ) {
  39. const { logError } = useLogger()
  40. const proto = new Loader()
  41. if (cb) {
  42. cb(proto)
  43. }
  44. if (extensions) {
  45. extensions(proto)
  46. }
  47. const paths = (Array.isArray(url) ? url : [url]) as string[]
  48. const results = paths.map(
  49. path =>
  50. new Promise((resolve, reject) => {
  51. proto.load(
  52. path,
  53. data => {
  54. if (data.scene) {
  55. Object.assign(data, trasverseObjects(data.scene))
  56. }
  57. resolve(data)
  58. },
  59. onProgress,
  60. (error: ErrorEvent) => reject(logError('[useLoader] - Failed to load resource', error as unknown as Error)),
  61. )
  62. }),
  63. )
  64. return (isArray(url) ? await Promise.all(results) : await results[0]) as U extends any[]
  65. ? LoaderReturnType<T, T>[]
  66. : LoaderReturnType<T, T>
  67. }