UNPKG

@babylonjs/viewer

Version:

The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.

377 lines (374 loc) 12.8 kB
import { r as retireGpuResources } from './index-By0tcgYN.esm.js'; const byOrder = (a, b) => a.order - b.order; let _builderTails = null; let _runtimeRebuilders = null; function A(scene, material, mesh, pending) { if (!material || mesh.material !== material) { return pending ?? Promise.resolve(); } const current = B(scene, material._buildGroup, mesh); return pending ? Promise.all([pending, current]).then(() => void 0) : current; } function B(scene, builder, mesh) { if (scene._z || !scene.meshes.includes(mesh)) { return scene._runtimeBuilds?.all().catch(() => void 0) ?? Promise.resolve(); } moveRuntimeMeshToGroup(scene, builder, mesh); if (builder._materialFamily === "pbr" && (scene._built || scene._groups.get(builder)?.r)) { const hooks2 = scene._runtimeBuilds ?? installRuntimeBuilds(scene); const rebuild = import('./index-By0tcgYN.esm.js').then(function (n) { return n.bn; }).then(({ rebuildScenePbrPipelines }) => scene._z ? void 0 : rebuildScenePbrPipelines(scene, true)).catch((error) => { scene._runtimeBuilds?._x(error); }); return hooks2.track(rebuild); } const hooks = scene._runtimeBuilds ?? installRuntimeBuilds(scene); return hooks.queue(builder, mesh).catch(() => void 0); } function X(scene, builder, work) { if (scene._z) { return Promise.resolve(void 0); } return (scene._runtimeBuilds ?? installRuntimeBuilds(scene)).exclusive(builder, work); } function installRuntimeBuilds(scene) { const state = { disposed: false, error: null, active: /* @__PURE__ */ new Set(), chains: /* @__PURE__ */ new WeakMap(), generations: /* @__PURE__ */ new WeakMap(), installed: /* @__PURE__ */ new WeakMap(), installedMeshes: /* @__PURE__ */ new Set(), tail: null }; const pbrState = scene; const hooks = { queue: (builder, mesh) => { const generation = (state.generations.get(mesh) ?? 0) + 1; const material = mesh.material; state.generations.set(mesh, generation); const previous = state.chains.get(mesh); const waits = [state.tail, _builderTails?.get(builder)].filter((wait) => !!wait); let release = () => void 0; const reservation = new Promise((resolve) => { release = resolve; }); state.tail = reservation; (_builderTails ??= /* @__PURE__ */ new WeakMap()).set(builder, reservation); const request = (previous ? previous.catch(() => void 0) : Promise.resolve()).then(() => Promise.all(waits)).then(() => materializeRuntimeMesh(scene, state, builder, mesh, material, generation)).catch((error) => { if (isLiveRequest(scene, state, builder, mesh, material, generation)) { state.error = error instanceof Error ? error : new Error("Runtime mesh build failed", { cause: error }); } throw error; }).finally(() => { release(); if (state.tail === reservation) { state.tail = null; } if (_builderTails?.get(builder) === reservation) { _builderTails.delete(builder); } }); const tracked = request.finally(() => { if (state.chains.get(mesh) === tracked) { state.chains.delete(mesh); } }); state.chains.set(mesh, tracked); return hooks.track(tracked); }, all: () => Promise.all(state.active).then(() => void 0), track: (promise) => { const tracked = promise.finally(() => state.active.delete(tracked)); state.active.add(tracked); return Promise.all(state.active).then(() => void 0); }, base: (builder, rebuild) => { const runtime = _runtimeRebuilders?.get(builder); if (runtime) { runtime.bases.set(scene, rebuild); } return runtime?.dispatch ?? rebuild; }, get w() { return !!state.tail; }, reset: (mesh) => { resetRuntimeRebuild(scene, state, mesh); pbrState._pbrMeshGeomContexts?.delete(mesh); }, remove: (mesh) => { state.generations.set(mesh, (state.generations.get(mesh) ?? 0) + 1); state.chains.delete(mesh); clearRuntimeRebuild(scene, state, mesh); pbrState._pbrMeshGeomContexts?.delete(mesh); }, wait: async (meshes) => { const pending = /* @__PURE__ */ new Set(); for (const mesh of meshes) { const task = state.chains.get(mesh); if (task) { pending.add(task); } } await Promise.all(pending); }, _e: (clear = true) => { if (state.error) { const error = state.error; if (clear) { state.error = null; } throw error; } }, _x: (error) => { state.error = error instanceof Error ? error : new Error("Runtime mesh build failed", { cause: error }); }, _d: () => state.disposed, exclusive: (builder, work) => { const waits = []; if (state.tail) { waits.push(state.tail); } const builderTail = _builderTails?.get(builder); if (builderTail) { waits.push(builderTail); } const task = Promise.all(waits).then(work); const tail = task.then( () => void 0, () => void 0 ); state.tail = tail; (_builderTails ??= /* @__PURE__ */ new WeakMap()).set(builder, tail); void tail.then(() => { if (state.tail === tail) { state.tail = null; } if (_builderTails?.get(builder) === tail) { _builderTails.delete(builder); } }); return task; } }; scene._runtimeBuilds = hooks; (scene._beforeRender ??= []).push(() => { hooks._e(); }); scene._disposables.push(() => { state.disposed = true; state.active.clear(); for (const mesh of state.installedMeshes) { resetRuntimeRebuild(scene, state, mesh); } for (const builder of scene._groups.keys()) { _runtimeRebuilders?.get(builder)?.bases.delete(scene); } scene._runtimeBuilds = void 0; pbrState._pbrMeshGeomContexts = void 0; }); return hooks; } function moveRuntimeMeshToGroup(scene, builder, mesh) { for (const [groupBuilder, meshes] of scene._groups) { if (groupBuilder !== builder) { const index = meshes.indexOf(mesh); if (index >= 0) { meshes.splice(index, 1); } } } let target = scene._groups.get(builder); if (!target) { target = []; scene._groups.set(builder, target); } if (!target.includes(mesh)) { target.push(mesh); } } async function materializeRuntimeMesh(scene, state, builder, mesh, material, generation) { if (!isLiveRequest(scene, state, builder, mesh, material, generation)) { return; } const previousDisposers = scene._meshDisposables.get(mesh); if (previousDisposers) { scene._meshDisposables.delete(mesh); } const previousRebuild = builder._rebuildSingle; const runtimeRebuilder = _runtimeRebuilders?.get(builder); const previousSceneBase = runtimeRebuilder?.bases.get(scene) ?? scene._groups.get(builder)?.r; const hadBuiltGroup = !!scene._groups.get(builder)?.r; const disposableStart = scene._disposables.length; const pbrState = scene; const previousPbrContext = pbrState._pbrGeomContext; let builtPbrContext; let result; try { result = await builder(scene, [mesh]); builtPbrContext = pbrState._pbrGeomContext; } catch (error) { discardMeshBuild(scene, state, mesh, previousDisposers); discardDisposedSceneCallbacks(scene, state); if (!isLiveRequest(scene, state, builder, mesh, material, generation)) { return; } throw error; } finally { builder._rebuildSingle = previousRebuild; if (builder._materialFamily === "pbr" && hadBuiltGroup) { pbrState._pbrGeomContext = previousPbrContext; } } if (!isLiveRequest(scene, state, builder, mesh, material, generation)) { discardMeshBuild(scene, state, mesh, previousDisposers); discardDisposedSceneCallbacks(scene, state); return; } for (let i = scene._renderables.length - 1; i >= 0; i--) { if (scene._renderables[i].mesh === mesh) { scene._renderables.splice(i, 1); } } if (previousDisposers) { for (const dispose of previousDisposers) { const packet = dispose.p; if (packet) { packet._disposed = true; const owner = packet._owner; if (owner) { const index = owner.indexOf(packet); if (index >= 0) { owner.splice(index, 1); } packet._owner = void 0; } } } retireGpuResources(scene.surface.engine, () => { for (const dispose of previousDisposers) { dispose(); } }); } scene._renderables.push(...result.renderables); if (result.updater) { scene._uniformUpdaters.push(result.updater); } if (hadBuiltGroup) { dedupeGroupCleanup(scene, disposableStart); } if (builder._materialFamily === "pbr" && hadBuiltGroup && builtPbrContext) { (pbrState._pbrMeshGeomContexts ??= /* @__PURE__ */ new WeakMap()).set(mesh, builtPbrContext); } installRuntimeRebuild(scene, state, builder, mesh, result.rebuildSingle, hadBuiltGroup ? previousSceneBase ?? previousRebuild : result.rebuildSingle); mesh.material._csmGen = (mesh.material._csmGen ?? 0) + 1; const group = scene._groups.get(builder); if (group && !hadBuiltGroup) { group.r = result.rebuildSingle; } scene._renderables.sort(byOrder); scene._renderableVersion++; scene._materialEpoch++; } function installRuntimeRebuild(scene, state, builder, mesh, rebuild, sceneBase) { let runtime = _runtimeRebuilders?.get(builder); if (!runtime) { const scenes = /* @__PURE__ */ new WeakMap(); const bases = /* @__PURE__ */ new WeakMap(); const dispatch = (targetScene, targetMesh, override) => { const specialized = scenes.get(targetScene)?.get(targetMesh); if (specialized) { return specialized(targetScene, targetMesh, override); } const base = bases.get(targetScene) ?? targetScene._groups.get(builder)?.r; if (base) { return base(targetScene, targetMesh, override); } throw new Error("Material group has not completed its initial build"); }; runtime = { bases, dispatch, scenes }; (_runtimeRebuilders ??= /* @__PURE__ */ new WeakMap()).set(builder, runtime); } let meshes = runtime.scenes.get(scene); if (!meshes) { meshes = /* @__PURE__ */ new WeakMap(); runtime.scenes.set(scene, meshes); } meshes.set(mesh, rebuild); if (!runtime.bases.has(scene)) { runtime.bases.set(scene, sceneBase ?? rebuild); } const group = scene._groups.get(builder); if (group) { group.r = runtime.dispatch; } let installed = state.installed.get(mesh); if (!installed) { installed = /* @__PURE__ */ new Set(); state.installed.set(mesh, installed); } installed.add(builder); state.installedMeshes.add(mesh); } function clearRuntimeRebuild(scene, state, mesh) { const builders = state.installed.get(mesh); if (builders) { for (const builder of builders) { _runtimeRebuilders?.get(builder)?.scenes.get(scene)?.delete(mesh); } state.installed.delete(mesh); state.installedMeshes.delete(mesh); } } function resetRuntimeRebuild(scene, state, mesh) { clearRuntimeRebuild(scene, state, mesh); } function isLiveRequest(scene, state, builder, mesh, material, generation) { return !state.disposed && state.generations.get(mesh) === generation && scene.meshes.includes(mesh) && mesh.material === material && material._buildGroup === builder; } function discardMeshBuild(scene, state, mesh, previousDisposers) { const builtDisposers = scene._meshDisposables.get(mesh); if (builtDisposers && builtDisposers !== previousDisposers) { scene._meshDisposables.delete(mesh); for (const dispose of builtDisposers) { dispose(); } } if (previousDisposers) { if (scene.meshes.includes(mesh)) { scene._meshDisposables.set(mesh, previousDisposers); } else if (state.disposed) { for (const dispose of previousDisposers) { dispose(); } } else { retireGpuResources(scene.surface.engine, () => { for (const dispose of previousDisposers) { dispose(); } }); } } } function discardDisposedSceneCallbacks(scene, state) { if (!state.disposed) { return; } const callbacks = scene._disposables.splice(0); for (const dispose of callbacks) { dispose(); } } function dedupeGroupCleanup(scene, start) { const existing = new Set(scene._disposables.slice(0, start)); for (let i = scene._disposables.length - 1; i >= start; i--) { if (existing.has(scene._disposables[i])) { scene._disposables.splice(i, 1); } } } export { A, B, X }; //# sourceMappingURL=scene-runtime-mesh-build-BgjG-8pT.esm.js.map