@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
JavaScript
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