UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

101 lines (77 loc) 3.34 kB
import { Mesh, Object3D } from "three"; import { type GLTF, type GLTFLoaderPlugin, GLTFParser } from "three/examples/jsm/loaders/GLTFLoader.js"; import { getParam } from "../engine_utils.js"; const $loadingId = Symbol("gltf-loader-internal-usage-tracker"); const debug = getParam("debugusers"); export class InternalUsageTrackerPlugin implements GLTFLoaderPlugin { get name(): string { return "NEEDLE_internal_usage_tracker"; } static isLoading(object: object) { return InternalUsageTrackerPlugin._loadingProcesses > 0; return object[$loadingId] !== undefined; } private static _loadingProcesses = 0; private readonly parser: GLTFParser; private readonly _getDependency: any; private readonly _loadingId: string; private _loadedObjects: Set<object> = new Set(); constructor(parser: GLTFParser) { this.parser = parser; this._getDependency = this.parser.getDependency; this._loadingId = Date.now().toString() } beforeRoot() { InternalUsageTrackerPlugin._loadingProcesses++; const self = this; // Patch parser get dependency to track all objects that have been loaded or created const getDependency = this._getDependency; this.parser.getDependency = function (type: string, index: number) { const promise = getDependency.call(this, type, index); promise.then((result) => { if (result) { self._loadedObjects.add(result); result[$loadingId] = self._loadingId; } return result; }); return promise; }; return null; } afterRoot(_result: GLTF) { InternalUsageTrackerPlugin._loadingProcesses--; // reset original method this.parser.getDependency = this._getDependency; // Cleanup usage of objects that have not been used in a scene for (const loaded of this._loadedObjects) { delete loaded[$loadingId]; if (loaded instanceof Object3D) { if (!loaded.parent) { if (loaded instanceof Mesh) { // we need to delay this for other plugins to use the mesh // TODO: do we even need to do this? setTimeout(() => { if (debug) console.warn("> GLTF LOADER: Mesh not used in scene!", loaded); loaded.material = null; loaded.geometry = null; }, 1000) } } } } return null; } // private readonly _creatingNodeMesh: Map<number, CreateNodeMesh> = new Map(); // createNodeMesh(_nodeIndex: number): CreateNodeMesh | null { // // if (!this.parser) return null; // // let process = this._creatingNodeMesh.get(nodeIndex); // // if (process) return process; // // process = this.parser.createNodeMesh(nodeIndex)?.then((mesh) => { // // console.log("createNodeMesh", nodeIndex, mesh); // // return mesh; // // }) as CreateNodeMesh; // // this._creatingNodeMesh.set(nodeIndex, process); // // return process; // } }