threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
72 lines (61 loc) • 2.64 kB
text/typescript
import {IViewerPluginSync} from '../../viewer'
import {SimpleEventDispatcher} from 'ts-browser-helpers'
/**
* Loads the MeshOpt Decoder module from [meshoptimizer](https://github.com/zeux/meshoptimizer) library at runtime from a customisable cdn url.
* 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
*
* The plugin name includes GLTF, but its not really GLTF specific, it can be used to decode any meshopt compressed files.
*/
export class GLTFMeshOptDecodePlugin extends SimpleEventDispatcher<'initialized'> implements IViewerPluginSync {
declare ['constructor']: typeof GLTFMeshOptDecodePlugin
public static readonly PluginType = 'GLTFMeshOptDecodePlugin'
enabled = true
toJSON: any = undefined
constructor(initialize = true, public readonly rootNode = document.head) {
super()
// todo: check if compatible?
if (initialize) this.initialize()
}
get initialized() {
return !!window.MeshoptDecoder
}
// static DECODER_URL = 'https://cdn.jsdelivr.net/gh/zeux/meshoptimizer@master/js/meshopt_decoder.module.js'
static DECODER_URL = 'https://unpkg.com/meshoptimizer@0.20.0/meshopt_decoder.module.js'
protected _script?: HTMLScriptElement
protected _initializing?: Promise<void> = undefined
async initialize() {
if (this.initialized) return
if (this._initializing) return await this._initializing
const s = document.createElement('script')
s.type = 'module'
const ev = Math.random().toString(36).substring(7)
s.innerHTML = `
import { MeshoptDecoder } from ${JSON.stringify(GLTFMeshOptDecodePlugin.DECODER_URL)};
window.MeshoptDecoder = MeshoptDecoder; // setting it before ready as GLTFLoader supports it.
MeshoptDecoder.ready.then(() => {
window.dispatchEvent(new CustomEvent('${ev}'))
});
`
this._initializing = new Promise<void>((res) => {
window.addEventListener(ev, ()=>res(), {once: true})
this.rootNode.appendChild(s)
this._script = s
})
await this._initializing
this.dispatchEvent({type: 'initialized'})
}
dispose() {
if (this._script) {
this._script.remove()
delete window.MeshoptDecoder
}
this._script = undefined
}
onAdded(): void { return }
onRemove(): void { return }
}
declare global{
interface Window{
MeshoptDecoder?: any
}
}