threepipe
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GLTFMeshOptDecodePlugin.ts 2.5KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import {IViewerPluginSync} from '../../viewer'
  2. import {SimpleEventDispatcher} from 'ts-browser-helpers'
  3. /**
  4. * Loads the MeshOpt Decoder module from [meshoptimizer](https://github.com/zeux/meshoptimizer) library at runtime from a customisable cdn url.
  5. * The loaded module is set in window.MeshoptDecoder and then used by {@link GLTFLoader2} to decode files using [EXT_meshopt_compression](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Vendor/EXT_meshopt_compression/README.md) extension
  6. *
  7. * The plugin name includes GLTF, but its not really GLTF specific, it can be used to decode any meshopt compressed files.
  8. */
  9. export class GLTFMeshOptDecodePlugin extends SimpleEventDispatcher<''> implements IViewerPluginSync {
  10. declare ['constructor']: typeof GLTFMeshOptDecodePlugin
  11. public static readonly PluginType = 'GLTFMeshOptDecodePlugin'
  12. enabled = true
  13. toJSON: any = undefined
  14. constructor(initialize = true, public readonly rootNode = document.head) {
  15. super()
  16. // todo: check if compatible?
  17. if (initialize) this.initialize()
  18. }
  19. get initialized() {
  20. return !!window.MeshoptDecoder
  21. }
  22. // static DECODER_URL = 'https://cdn.jsdelivr.net/gh/zeux/meshoptimizer@master/js/meshopt_decoder.module.js'
  23. static DECODER_URL = 'https://unpkg.com/meshoptimizer@0.20.0/meshopt_decoder.module.js'
  24. protected _script?: HTMLScriptElement
  25. protected _initializing?: Promise<void> = undefined
  26. async initialize() {
  27. if (this.initialized) return
  28. if (this._initializing) return await this._initializing
  29. const s = document.createElement('script')
  30. s.type = 'module'
  31. const ev = Math.random().toString(36).substring(7)
  32. s.innerHTML = `
  33. import { MeshoptDecoder } from '${GLTFMeshOptDecodePlugin.DECODER_URL}';
  34. window.MeshoptDecoder = MeshoptDecoder; // setting it before ready as GLTFLoader supports it.
  35. MeshoptDecoder.ready.then(() => {
  36. window.dispatchEvent(new CustomEvent('${ev}'))
  37. });
  38. `
  39. this._initializing = new Promise<void>((res) => {
  40. window.addEventListener(ev, ()=>res(), {once: true})
  41. this.rootNode.appendChild(s)
  42. this._script = s
  43. })
  44. return await this._initializing
  45. }
  46. dispose() {
  47. if (this._script) {
  48. this._script.remove()
  49. delete window.MeshoptDecoder
  50. }
  51. this._script = undefined
  52. }
  53. onAdded(): void { return }
  54. onRemove(): void { return }
  55. }
  56. declare global{
  57. interface Window{
  58. MeshoptDecoder?: any
  59. }
  60. }