Enable the Bhote Koshi event on Cesium while 3D tiles are shown

Under photoreal tiles Cesium hides the globe, so its imagery layers never
request tiles and the event's imagery install waited for a frame that
never came: turning the story on with 3D tiles on never finished. The
decoded images are installed hidden and shown afterwards by the same rule
as the presentation mode.
This commit is contained in:
German Khokhlov committed 2026-11-11 02:07:36 +04:00
1 parent c1795c7dc3
commit ed6b6114cf
2 files changed
+86 -1

No files matched your search

+10 -1
View File
@@ -1179,12 +1179,21 @@ export function createBhoteKoshiEventLayer({
_imageryImages = null;
throw new Error('Bhote Koshi imagery unavailable');
}
// These decoded images replace empty layers. Install them hidden so a
// tileset with no imagery requests cannot hold enable behind a drawn frame.
_native.setVisible(false);
await _native.loadImages(
event.imagery.rectangle,
images,
'Vantor WorldView Open Data · CC BY-NC 4.0',
);
if (_enabled && current()) setSplit(_split);
if (_enabled && current()) {
_native.setVisible(
_presentation !== BHOTE_KOSHI_SCENE_PRESENTATION ||
_sceneControls.imageryComparison === true,
);
setSplit(_split);
}
}
async function resolveEvidenceAnchors(event, signal) {
+76
View File
@@ -36,6 +36,8 @@ import { SCENE_RECIPES } from '../scenes/recipes.js';
import { LayerLifecycle } from './lifecycle.js';
import { createBhoteKoshiEmbeddedMedia } from './bhoteKoshiEmbeddedMedia.js';
import { SceneDirector } from '../scenes/director.js';
import { createCesiumImagery } from '../globe/cesium/imagery.js';
import { createBhoteKoshiDisplay } from '../layers/bhoteKoshi/render/display.js';
const eventUrl = new URL('../../public/events/bhote-koshi-2026/event.json', import.meta.url);
const eventModuleUrl = new URL('./bhoteKoshiEvent.js', import.meta.url);
@@ -3258,6 +3260,80 @@ async function navaraEvidenceCard({ sample, signal }) {
};
}
for (const presentation of ['standalone', 'scene-beat']) {
test(`Bhote Koshi enables ${presentation} without waiting for tileset imagery requests`, async () => {
const originalDocument = globalThis.document;
const originalWindow = globalThis.window;
installEventDom();
globalThis.window = { setTimeout: () => 1, clearTimeout() {} };
const event = JSON.parse(await readFile(eventUrl, 'utf8'));
event.evidenceSpine = [];
const engine = createFakeEngine({ canvas: eventViewer().scene.canvas });
const viewer = {
imageryLayers: new Cesium.ImageryLayerCollection(),
scene: {
globe: { show: false },
preRender: new Cesium.Event(),
preUpdate: new Cesium.Event(),
postRender: new Cesium.Event(),
},
};
const tileset = {
show: true,
imageryLayers: new Cesium.ImageryLayerCollection(),
isDestroyed: () => false,
};
const imagery = createCesiumImagery(viewer, {
requestRender() {},
tilesets: () => [tileset],
createCanvas: (width, height) => ({
width, height,
getContext: () => ({
createImageData: (w, h) => ({ data: new Uint8ClampedArray(w * h * 4) }),
putImageData() {},
}),
}),
});
engine.imagery = imagery.imagery;
let display;
const layer = buildEventLayer({
eventLoader: async () => event,
imageLoader: async () => ({ width: 1, height: 1, data: new Uint8Array(4) }),
createNativeRenderer: (engine) => (display = createBhoteKoshiDisplay(engine)),
embeddedMediaFactory: () => ({ hide() {}, pause() {}, destroy() {} }),
overlayHost: { setEntries() {}, setVisible() {}, clearSource() {} },
renderHost: { request() {}, hold() {}, release() {} },
});
let enabling;
try {
await layer.init(null, { engine });
layer.setParams({ presentation, sceneSurface: 'evidence-beat', autoPlay: false });
let enabled = false;
enabling = layer.enable(null).then(() => { enabled = true; });
await new Promise(setImmediate);
assert.equal(enabled, true, 'decoded images must not wait for an undrawable stage');
const images = engine.imagery.list();
assert.equal(images.length, 2);
assert.equal(tileset.imageryLayers.length, 2, 'no staged layers remain');
for (const image of images)
assert.equal(image.shown, presentation === 'standalone');
await layer.detachRenderer();
let attached = false;
enabling = layer.attachRenderer({ engine }).then(() => { attached = true; });
await new Promise(setImmediate);
assert.equal(attached, true, 'reattachment does not wait for imagery requests either');
} finally {
display?.setVisible(false);
await enabling;
await layer.destroy();
imagery.destroy();
engine.destroy();
globalThis.document = originalDocument;
globalThis.window = originalWindow;
}
});
}
test('Navara evidence anchors stand on the most detailed terrain', async () => {
const originalDocument = globalThis.document;
const originalWindow = globalThis.window;